Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

computing the end of an array

6 views
Skip to first unread message

J. Wesley

unread,
Jul 6, 1998, 3:00:00 AM7/6/98
to

is there anyway to convert the following template function and macro...

template <class T> size_t sizeof_array_type(const T*) { return
sizeof(T); };
#define end_of(foo) foo+sizeof(foo)/sizeof_array_type(foo)

into a template-only solution? i'm still stumped after many attempts.

a possible use of such a solution...

#include <algorithm>
#include <iostream>

template <class T> size_t sizeof_array_type(const T*) { return
sizeof(T); };
#define end_of(foo) foo+sizeof(foo)/sizeof_array_type(foo)

struct test { int x; char* y; };
test array[] = { {1, "first"}, {2, "second"}, {0, "" }, };

void print_test(const test& t)
{
std::cout << t.x << ", " << t.y << std::endl;
}

void main(int argc, char* argv[])
{
std::for_each(array, end_of(array)-1, print_test);
}

thanks for any help you may provide!

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Siemel Naran

unread,
Jul 7, 1998, 3:00:00 AM7/7/98
to
>is there anyway to convert the following template function and macro...
>
> template <class T> size_t sizeof_array_type(const T*) { return
>sizeof(T); };
> #define end_of(foo) foo+sizeof(foo)/sizeof_array_type(foo)
>
>into a template-only solution? i'm still stumped after many attempts.


Why? In the above macro, it appears that "foo" is a builtin C++ array.
Because if "foo" were a pointer (i.e. possibly an array of arbitrary
size), then sizeof(foo) would just be the size of the pointer itself,
which on my system is 4 bytes.

So if "foo" is a builtin C++ array, then

template <class T, size_t N>
inline size_t end_of(const T (&array)[N]) { return N; }

Note that sizeof(array)=sizeof(T)*N.

Since you typically know what N is when you write the array, the above
function is unncessary.

>#include <algorithm>
>#include <iostream>
>
>template <class T> size_t sizeof_array_type(const T*) { return
>sizeof(T); };
>#define end_of(foo) foo+sizeof(foo)/sizeof_array_type(foo)
>
>struct test { int x; char* y; };
>test array[] = { {1, "first"}, {2, "second"}, {0, "" }, };

Avoid declaring a terminator struct if you can. It just eats up space,
and time especially if it has a non-trivial constructor.
test array[] = { {1, "first"}, {2, "second"} };

Variable "array" contains two elements. This constant is known at
compile time. The compiler has done the counting for you. If you
want to know what this number is without manually counting the
array, do either of these:
const int N=sizeof(array)/sizeof(array[0]);
const int N=sizeof(array)/sizeof(test );


>void print_test(const test& t)
>{
> std::cout << t.x << ", " << t.y << std::endl;
>}
>
>void main(int argc, char* argv[])
>{
> std::for_each(array, end_of(array)-1, print_test);

If you didn't use the terminator struct, and you declared the const
variable N, then this should work:
std::for_each(array, array+N, print_test);

>}

If you want to pass the array to a function, use the template<int>
example at the top of this message.

template <int N>
void (const test (&array)[N]) { ... }

--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

Gerhard Menzl

unread,
Jul 7, 1998, 3:00:00 AM7/7/98
to
J. Wesley wrote:

> is there anyway to convert the following template function and macro...
>
> template <class T> size_t sizeof_array_type(const T*) { return
> sizeof(T); };
> #define end_of(foo) foo+sizeof(foo)/sizeof_array_type(foo)
>
> into a template-only solution? i'm still stumped after many attempts.

Yes: std::vector. Its end() member function returns an iterator one past
the last element. The functions from <algorithm> are designed to work
best
with iterators, so unless there is some compelling reason for a C-style
array, STL containers are your best bet.

Gerhard Menzl

dietma...@claas-solutions.de

unread,
Jul 7, 1998, 3:00:00 AM7/7/98
to
Hi,
In article <083o1.1255$8h.171...@newsreader.digex.net>,

"J. Wesley" <joel...@no.spam.yahoo.com> wrote:
> is there anyway to convert the following template function and
macro...
>
> template <class T> size_t sizeof_array_type(const T*) { return
> sizeof(T); };
> #define end_of(foo) foo+sizeof(foo)/sizeof_array_type(foo)
>
> into a template-only solution? i'm still stumped after many attempts.

Something like a year ago, I posted a solution to exactly this problem:

template <class T, size_t sz>
inline size_t size(T (&array)[sz]) { return sz; }
template <class T, size_t sz>
inline T *begin(T (&array)[sz]) { return array; }
template <class T, size_t sz>
inline T *end(T (&array)[sz]) { return array + sz; }

Of course, this works only if an array object is passed to these
function. It
does not work if a pointer is used as argument: In C++ there is no way
to
determine the size of an object from a pointer, at least no standard one
(implementations normally can tell the size but there is no way to
access this
information).

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum

jka...@otelo.ibmmail.com

unread,
Jul 8, 1998, 3:00:00 AM7/8/98
to
In article <slrn6q2465....@bardeen.ceg.uiuc.edu>,

sbn...@uiuc.edu wrote:
> >is there anyway to convert the following template function and macro...
> >
> > template <class T> size_t sizeof_array_type(const T*) { return
> >sizeof(T); };
> > #define end_of(foo) foo+sizeof(foo)/sizeof_array_type(foo)
> >
> >into a template-only solution? i'm still stumped after many attempts.
>
> Why? In the above macro, it appears that "foo" is a builtin C++ array.
> Because if "foo" were a pointer (i.e. possibly an array of arbitrary
> size), then sizeof(foo) would just be the size of the pointer itself,
> which on my system is 4 bytes.

foo must be a C style array.

> So if "foo" is a builtin C++ array, then
>
> template <class T, size_t N>
> inline size_t end_of(const T (&array)[N]) { return N; }
>
> Note that sizeof(array)=sizeof(T)*N.
>
> Since you typically know what N is when you write the array, the above
> function is unncessary.

Since you almost never know what N is when you write the array, the
above function is incredibly useful.

99% of my C style arrays are constants of the form:

static SomeType const array[] =
{
// initializers...
} ;

Generally speaking, the compiler can count better than I can, so I
don't specify the length. And it does change from one compile to the
next.

> >#include <algorithm>
> >#include <iostream>


> >
> >template <class T> size_t sizeof_array_type(const T*) { return
> >sizeof(T); };
> >#define end_of(foo) foo+sizeof(foo)/sizeof_array_type(foo)
> >

> >struct test { int x; char* y; };
> >test array[] = { {1, "first"}, {2, "second"}, {0, "" }, };
>
> Avoid declaring a terminator struct if you can. It just eats up space,
> and time especially if it has a non-trivial constructor.

If the array is static, this time occurs just once. And on the machines
I work on now, space isn't an issue. Depending on what you are doing,
using a sentinal may be significantly faster and/or easier.

One useful idiom here is to declare the array non-const, ensure that
the last element contains the default handler, and insert the key you're
looking for into the last element before searching.

--
James Kanze +33 (0)1 39 23 84 71 mailto: ka...@gabi-soft.fr
+49 (0)69 66 45 33 10 mailto: jka...@otelo.ibmmail.com
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orientée objet --
-- Beratung in objektorientierter Datenverarbeitung

Siemel Naran

unread,
Jul 10, 1998, 3:00:00 AM7/10/98
to
>> template <class T, size_t N>
>> inline size_t end_of(const T (&array)[N]) { return N; }
>> Note that sizeof(array)=sizeof(T)*N.

>> Since you typically know what N is when you write the array, the above
>> function is unncessary.

>Since you almost never know what N is when you write the array, the
>above function is incredibly useful.

I mean that we know it indirectly. Indeed, we usually never count
the number of elements in the array manually. But if we embed the
above function "size_of" in our code directly, isn't it guaranteed
to be a compile time constant.

int array[] = { 1,2,3,4 };
const int N=sizeof(array)/sizeof(array[0]); // N=4 at compile time (?)
double array[N];

int array[] = { 1,2,3,4 };
const int N=size_of(array); // not an integral constant
double array[N]; // error
// see "functions in constant expressions" on comp.std.c++


--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

dietma...@claas-solutions.de

unread,
Jul 20, 1998, 3:00:00 AM7/20/98
to
Hi,
In article <slrn6qahrh....@fermi.ceg.uiuc.edu>,

sbn...@KILL.uiuc.edu wrote:
> int array[] = { 1,2,3,4 };
> const int N=size_of(array); // not an integral constant
> double array[N]; // error
> // see "functions in constant expressions" on comp.std.c++

This problem can be removed by using an approach slightly more involved:

template <size_t sz>
struct array_size { enum { size = sz }; };
template <typename T, size_t sz>
array_size<sz> size(T (&array)[sz]) { return array_size<sz>(); }

int iarray[] = { 1, 2, 3, 4 };
double darray[size(iarray)::size];
--
<mailto:dietma...@claas-solutions.de>
homepage: <http://www.informatik.uni-konstanz.de/~kuehl>

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Nathan Myers

unread,
Jul 21, 1998, 3:00:00 AM7/21/98
to
<dietma...@claas-solutions.de> wrote:
> template <size_t sz>
> struct array_size { enum { size = sz }; };
> template <typename T, size_t sz>
> array_size<sz> size(T (&array)[sz]) { return array_size<sz>(); }
>
> int iarray[] = { 1, 2, 3, 4 };
> double darray[size(iarray)::size];

The code above is rejected by my compilers. (They complain about
the use of the size() function in a compile-time constant expression.
However, this works:

template <size_t N> struct Asbigas { int junk[N]; };
template <typename T, size_t N> Asbigas<N> sizer(T (&)[N]); // not
defined
template <size_t N>
struct Size { enum { size = N/sizeof(int) }; };



int iarray[] = { 1, 2, 3, 4 };

double darray[ Size<sizeof(sizer(iarray))>::size ];

I don't know if "Size<sizeof(sizer(iarray))>::size"
is better than "sizeof(iarray)/sizeof(*iarray)".

--
Nathan Myers
n...@nospam.cantrip.org http://www.cantrip.org/

Siemel Naran

unread,
Jul 22, 1998, 3:00:00 AM7/22/98
to

[dietmar]

> template <size_t sz>
> struct array_size { enum { size = sz }; };
> template <typename T, size_t sz>
> array_size<sz> size(T (&array)[sz]) { return array_size<sz>(); }
>
> int iarray[] = { 1, 2, 3, 4 };
> double darray[size(iarray)::size];

From one point of view, the above is still not an integral constant
because it involves a call to the constructor and destructor. Surely,
these silly calls can be optimized away at compile time. But when the
context of the program requires a compile-time constant, the compiler
has
to pretend that the optimizations don't occur.

"size(iarray)" creates an object using array_size<4u>::array_size()
"size(iarray)::size" accesses static const data of the returned struct,
so
it's a compile time constant
now the destructor array_size<4u>::~array_size() is called


From another point of view, the argument of the square brackets is a
compile time constant, as "size" is static const data. So,
optimizations
aside, the code should compile. This is pretty much what g++ does, even
with the --pedantic switch. But we have to say "[size(iarray).size]".
The use of the "::" is a syntax error on g++, although I don't think it
should be.


Not sure which point of view is correct (#1 seems more correct to me).
But note that
double darray[sizeof(iarray)/sizeof(iarray[0])];
seems much simpler to me.


[dietmar]


>> template <size_t sz>
>> struct array_size { enum { size = sz }; };
>> template <typename T, size_t sz>
>> array_size<sz> size(T (&array)[sz]) { return array_size<sz>(); }
>>
>> int iarray[] = { 1, 2, 3, 4 };
>> double darray[size(iarray)::size];

>The code above is rejected by my compilers. (They complain about
>the use of the size() function in a compile-time constant expression.

So your compilers take point of view #1. My compiler takes point of
view #2.


>However, this works:
>
> template <size_t N> struct Asbigas { int junk[N]; };
> template <typename T, size_t N> Asbigas<N> sizer(T (&)[N]); // not
>defined
> template <size_t N>
> struct Size { enum { size = N/sizeof(int) }; };
>
> int iarray[] = { 1, 2, 3, 4 };
> double darray[ Size<sizeof(sizer(iarray))>::size ];

Yuck.

What seems strange about these functions like "sizer" and "Size" from
an aesthetic principle is that they don't use all the arguments that
they take. (Note that we're treating functions, variables, and types
as one and the same thing here, which seems to be a good idea).

>I don't know if "Size<sizeof(sizer(iarray))>::size"
>is better than "sizeof(iarray)/sizeof(*iarray)".

My char(2): Use the second line!


--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Paul D. DeRocco

unread,
Jul 22, 1998, 3:00:00 AM7/22/98
to
Nathan Myers wrote:
>
> template <size_t N> struct Asbigas { int junk[N]; };
> template <typename T, size_t N> Asbigas<N> sizer(T (&)[N]);
> template <size_t N>
> struct Size { enum { size = N/sizeof(int) }; };
>
> int iarray[] = { 1, 2, 3, 4 };
> double darray[ Size<sizeof(sizer(iarray))>::size ];

It's going to take me a while to figure that one out!

> I don't know if "Size<sizeof(sizer(iarray))>::size"
> is better than "sizeof(iarray)/sizeof(*iarray)".

If it rejects non-arrays, then it's better. And it's easily wrapped in a
macro to pretty it up:

#define lengthof(x) (Size<sizeof(sizer(x))>::size)

--

Ciao,
Paul

Nathan Myers

unread,
Jul 22, 1998, 3:00:00 AM7/22/98
to
Nathan Myers<n...@nospam.cantrip.org> wrote:

><dietma...@claas-solutions.de> wrote:
>> template <size_t sz>
>> struct array_size { enum { size = sz }; };
>> template <typename T, size_t sz>
>> array_size<sz> size(T (&array)[sz]) { return array_size<sz>(); }
>>
>> int iarray[] = { 1, 2, 3, 4 };
>> double darray[size(iarray)::size];
>
>The code above is rejected by my compilers. (They complain about
>the use of the size() function in a compile-time constant expression.
>However, this works:

>
> template <size_t N> struct Asbigas { int junk[N]; };
> template <typename T, size_t N> Asbigas<N> sizer(T (&)[N]);
> template <size_t N>
> struct Size { enum { size = N/sizeof(int) }; };
>
> int iarray[] = { 1, 2, 3, 4 };
> double darray[ Size<sizeof(sizer(iarray))>::size ];
>
>I don't know if "Size<sizeof(sizer(iarray))>::size"
>is better than "sizeof(iarray)/sizeof(*iarray)".

Actually, I _do_ know: "Size<sizeof(sizer(iarray))>::size" is
better because it doesn't allow iarray to be a pointer.

Yves Dufournaud

unread,
Jul 22, 1998, 3:00:00 AM7/22/98
to
Nathan Myers wrote:
>
> Nathan Myers<n...@nospam.cantrip.org> wrote:
> ><dietma...@claas-solutions.de> wrote:
> >> template <size_t sz>
> >> struct array_size { enum { size = sz }; };
> >> template <typename T, size_t sz>
> >> array_size<sz> size(T (&array)[sz]) { return array_size<sz>(); }
> >>
> >> int iarray[] = { 1, 2, 3, 4 };
> >> double darray[size(iarray)::size];
> >
> >The code above is rejected by my compilers. (They complain about
> >the use of the size() function in a compile-time constant expression.
> >However, this works:
> >
> > template <size_t N> struct Asbigas { int junk[N]; };
> > template <typename T, size_t N> Asbigas<N> sizer(T (&)[N]);
> > template <size_t N>
> > struct Size { enum { size = N/sizeof(int) }; };
> >
> > int iarray[] = { 1, 2, 3, 4 };
> > double darray[ Size<sizeof(sizer(iarray))>::size ];
> >
> >I don't know if "Size<sizeof(sizer(iarray))>::size"
> >is better than "sizeof(iarray)/sizeof(*iarray)".
>
> Actually, I _do_ know: "Size<sizeof(sizer(iarray))>::size" is
> better because it doesn't allow iarray to be a pointer.

Very interesting code, but why not use char instead of int, it gives :

template <size_t N>
struct Asbigas
{

char junk[N];
};

template <typename T, size_t N>
Asbigas<N> sizer(T (&)[N]);

int iarray[] = { 1, 2, 3, 4 };

double darray[ sizeof(sizer(iarray)) ];

now my question :
why and how does this work ?

sizer is a function with no body ?!

And second do the compiler allocate Asbigas or not ?

I'll try to answer myself :
I believe that sizeof applied on a prototype
return the size of the return type..
so there is no memory eat by this code.

right ?

Yves

--
PS : Remove "-o-" from the (reply) address to be able to respond

--
Yves Dufournaud Email Yves.Dufournaud at imag.fr equipe MOVI laboratoire
GRAVIR
--

Alessio Marchetti

unread,
Jul 23, 1998, 3:00:00 AM7/23/98
to
Nathan Myers wrote:
>
> <dietma...@claas-solutions.de> wrote:
> > template <size_t sz>
> > struct array_size { enum { size = sz }; };
> > template <typename T, size_t sz>
> > array_size<sz> size(T (&array)[sz]) { return array_size<sz>(); }
> >
> > int iarray[] = { 1, 2, 3, 4 };
> > double darray[size(iarray)::size];
>
> The code above is rejected by my compilers. (They complain about
> the use of the size() function in a compile-time constant expression.

Beside
double darray[size(iarray).size];
should be used instead of
double darray[size(iarray)::size];
since size(iarray) returns an array_size<> object.

--
Alessio Marchetti
E-mail: ale...@marchetti.net

Christopher Eltschka

unread,
Jul 23, 1998, 3:00:00 AM7/23/98
to
Yves Dufournaud wrote:

[...]

> Very interesting code, but why not use char instead of int, it gives :
>
> template <size_t N>
> struct Asbigas
> {
> char junk[N];
> };
>
> template <typename T, size_t N>
> Asbigas<N> sizer(T (&)[N]);
>

> int iarray[] = { 1, 2, 3, 4 };

> double darray[ sizeof(sizer(iarray)) ];
>
> now my question :
> why and how does this work ?
>

This as written AFAIK is not guaranteed to work as expected, since
the implementation is free to force a certain alignment for any
struct (f.ex. for performance reasons on word-addressed machines),
which may cause some padding be added to Asbigas (that is,
sizeof(Asbigas<N>) may be N rounded up to the next multiple of
the word size of a machine). However, I think the following
should work as expected:

double darray[ sizeof(sizer(iarray).junk) ];

This could then be wrapped into a macro again:

#define arr_length(array) sizeof(sizer(iarray).junk)

> sizer is a function with no body ?!

Since you're only interested in the return type, you don't need to
define it (I don't think there's a requirement to define each
declared function). However, if you'd define it, it wouldn't
hurt, since you don't call it anyway (the argument of sizeof is
not evaluated). Declaring but not defining it has the advantage
that if you accidentally call it anyway, you get a link error.

>
> And second do the compiler allocate Asbigas or not ?

Since the argument of sizeof is not evaluated, the return value
of sizer is not constructed. And since there's no other point in
the program where you use Asbigas, no object of type Asbigas will
be generated (you might get some names in the symbol table, though).

>
> I'll try to answer myself :
> I believe that sizeof applied on a prototype
> return the size of the return type..
> so there is no memory eat by this code.
>
> right ?

Yes. More generally, sizeof returns the size of the (static)
type of the expression it is applied to. Especially it doesn't
evaluate the expression (f.ex. sizeof (*(double*)0) is valid
and equivalent to sizeof(double), despite the null pointer
dereferencing, and sizeof(cout << "Hello" << endl) doesn't
output anything).

Siemel Naran

unread,
Jul 23, 1998, 3:00:00 AM7/23/98
to
>> template <size_t N> struct Asbigas { char junk[N]; };
>> template <typename T, size_t N> Asbigas<N> sizer(T (&)[N]);

>> int iarray[] = { 1, 2, 3, 4 };
>> double darray[ sizeof(sizer(iarray)) ];
>>
>> now my question :
>> why and how does this work ?

This was amazing. I gave struct Asbigas printing constructors and
destructors like this one
Asbigas::Asbigas() { cout<<"Asbigas::Asbigas()\n"; }
and nothing was printed!

Here's something from expr.sizeof, item (1):
The sizeof operator yields the number of bytes in the
object representation of its operand. The operand is
either an expression, which is not evaluated, or a
parenthesized type-id.
This excerpt says that the argument of a sizeof is not evaluated. Which
makes sense, because when you say sizeof(double), the program doesn't
create a double and then evaluate its size. The fact that the argument
is not evaluated implies that the sizeof 'function' -- it looks like a
function, after all -- is a guaranteed compile time constant with no
side effects.


>> I'll try to answer myself :
>> I believe that sizeof applied on a prototype
>> return the size of the return type..
>> so there is no memory eat by this code.
>>
>> right ?

>Yes. More generally, sizeof returns the size of the (static)
>type of the expression it is applied to. Especially it doesn't
>evaluate the expression (f.ex. sizeof (*(double*)0) is valid
>and equivalent to sizeof(double), despite the null pointer
>dereferencing, and sizeof(cout << "Hello" << endl) doesn't
>output anything).

>> sizer is a function with no body ?!

>Since you're only interested in the return type, you don't need to
>define it (I don't think there's a requirement to define each
>declared function). However, if you'd define it, it wouldn't
>hurt, since you don't call it anyway (the argument of sizeof is
>not evaluated). Declaring but not defining it has the advantage
>that if you accidentally call it anyway, you get a link error.


An additional point:


>This as written AFAIK is not guaranteed to work as expected, since
>the implementation is free to force a certain alignment for any
>struct (f.ex. for performance reasons on word-addressed machines),
>which may cause some padding be added to Asbigas (that is,
>sizeof(Asbigas<N>) may be N rounded up to the next multiple of
>the word size of a machine). However, I think the following
>should work as expected:
>
>double darray[ sizeof(sizer(iarray).junk) ];

Right, a struct can have padding. The size of an array of size N
is guaranteed to be N*sizeof(object). From item number (2)
When applied to an array, the result is the total number
of bytes in the array. This implies that the size of an
array of n elements is n times the size of an element.
But the struct can have a larger size, even if its only field is an
array. So that's why the junk qualifier is needed.


But how about this?

template <typename T, size_t N>

char ( & sizer(T(&)[N]) )[N];

char iarray[] = { 1, 2, 3 }; // sizeof=3*sizeof(char)=3
double darray[ sizeof(sizer(iarray)) ]; // sizeof=3*sizeof(double)

>This could then be wrapped into a macro again:
>#define arr_length(array) sizeof(sizer(iarray).junk)

No. Macros aren't good. What if we wanted this macro to be defined
only in the namespace util?

--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Nathan Myers

unread,
Jul 23, 1998, 3:00:00 AM7/23/98
to
Yves Dufournaud <Yves.Du...@imag.fr> wrote:
>Nathan Myers wrote:
>> >However, this works:
>> >
>> > template <size_t N> struct Asbigas { int junk[N]; };

>> > template <typename T, size_t N> Asbigas<N> sizer(T (&)[N]);
>> > template <size_t N>
>> > struct Size { enum { size = N/sizeof(int) }; };
>> >
>> > int iarray[] = { 1, 2, 3, 4 };
>> > double darray[ Size<sizeof(sizer(iarray))>::size ];

>
>Very interesting code, but why not use char instead of int, it gives :
>
>template <size_t N> struct Asbigas { char junk[N]; };
>template <typename T, size_t N> Asbigas<N> sizer(T (&)[N]);
>
>int iarray[] = { 1, 2, 3, 4 };
>double darray[ sizeof(sizer(iarray)) ];

Of course I considered that. Some implementations add padding,
so that for N==5, sizeof might yield 8.

Nathan Myers

unread,
Jul 24, 1998, 3:00:00 AM7/24/98
to
Siemel Naran<sbn...@KILL.uiuc.edu> wrote:
>But how about this?

>
>template <typename T, size_t N>
>char ( & sizer(T(&)[N]) )[N];
>
>char iarray[] = { 1, 2, 3 }; // sizeof=3*sizeof(char)=3
>double darray[ sizeof(sizer(iarray)) ]; // sizeof=3*sizeof(double)

I'm about ready to declare this officially the best solution
I've seen yet. However, it's incomplete. Here's the complete
definition:

template <typename T, size_t N>

char (& sizer(T(&)[N]))[N];


template <typename T, size_t N>

char (& sizer(T const (&)[N]))[N];

double a[sizeof(sizer(("abc"))];
double b[sizeof(sizer((a))];

Unfortunately, some current compilers will choke on this
for reasons that are extremely obscure. The EDG compilers
and next week's (:-) egcs snapshot read it correctly.

Don't forget to credit Dietmar Kuehl for the genesis of this idea,
when you mention or use it.

Alexandre Oliva

unread,
Jul 24, 1998, 3:00:00 AM7/24/98
to
Nathan Myers <n...@nospam.cantrip.org> writes:

> I'm about ready to declare this officially the best solution
> I've seen yet. However, it's incomplete. Here's the complete
> definition:

> template <typename T, size_t N>
> char (& sizer(T(&)[N]))[N];
> template <typename T, size_t N>
> char (& sizer(T const (&)[N]))[N];

I fail to understand why the `const' version is necessary. Wouldn't T
be made const when needed?

> double a[sizeof(sizer(("abc"))];
> double b[sizeof(sizer((a))];

^ these shouldn't be here, of course...

> next week's (:-) egcs snapshot read it correctly.

So do egcs 1.0.3a and gcc 2.8.1 :-)

--
Alexandre Oliva
mailto:ol...@dcc.unicamp.br mailto:aol...@acm.org
http://www.dcc.unicamp.br/~oliva
Universidade Estadual de Campinas, SP, Brasil

Esa Pulkkinen

unread,
Jul 24, 1998, 3:00:00 AM7/24/98
to
[In retrospect, I probably should not have approved the prior article. Please
consider this to be the end of thread. --mod]

n...@nospam.cantrip.org (Nathan Myers) writes:
> Don't forget to credit Dietmar Kuehl for the genesis of this idea,
> when you mention or use it.

Hmm... are you sure Dietmar was the first to use this technique?
[References please]. I ask because I've had a web page[1] since Aug 1997
about the same technique applied for getting the rank of an array, and
I'd like to know if I've missed some earlier references to this
technique (I'd like to add them to the web page). The earliest other
references I have are all from December 1997 (see dejanews, we had
similar discussion about this technique then...) It's also now described
in the KAI C++ User Guide[2] (I submitted a bug report to KAI in July
1997 because their compiler (3.2b) crashed trying to compile my solution
to the puzzle in their User Guide :)

[1] http://www.cs.tut.fi/~esap/instructive/array-rank.html
[2] http://www.kai.com/C_plus_plus/online_doc/UserGuide/
--
Esa Pulkkinen | C++ programmers do it virtually
E-Mail: es...@cs.tut.fi | everywhere with class, resulting
WWW : http://www.cs.tut.fi/~esap/ | in multiple inheritance.

Nathan Myers

unread,
Jul 25, 1998, 3:00:00 AM7/25/98
to
Alexandre Oliva <ol...@dcc.unicamp.br> wrote:
>Nathan Myers <n...@nospam.cantrip.org> writes:
>
>> I'm about ready to declare this officially the best solution
>> I've seen yet. However, it's incomplete. Here's the complete
>> definition:
>
>> template <typename T, size_t N>
>> char (& sizer(T(&)[N]))[N];
>> template <typename T, size_t N>
>> char (& sizer(T const (&)[N]))[N];
>
>I fail to understand why the `const' version is necessary. Wouldn't T
>be made const when needed?
>
>> double a[sizeof(sizer("abc"))];
>> double b[sizeof(sizer(a))];

Of course. My mistake. All Hail Dietmar Kuehl! All Hail Siemel Naran!

Chichiang Wan

unread,
Jul 26, 1998, 3:00:00 AM7/26/98
to
The following code to compute the size of array is pretty impressive:

template <size_t N> struct sizer { char c[N]; };
template <typename T, size_t N> sizer<N> sizer_func(T (&)[N]); //not
defined

int iarray[] = { 1, 2, 3, 4, 5, 6 };
float farray[] = { 1, 2, 3, 4, 5, 6, 7 };

sizeof(sizer_func(farray)));

In what ways is it better than sizeof(farray) / sizeof (farray[0]); ?

I know that the original posting asked for template-only solution.
There may be some practical reason for that ?

-- Chichiang

Siemel Naran

unread,
Jul 27, 1998, 3:00:00 AM7/27/98
to
>template <size_t N> struct sizer { char c[N]; };
>template <typename T, size_t N> sizer<N> sizer_func(T (&)[N]); //not
>defined
>
>int iarray[] = { 1, 2, 3, 4, 5, 6 };
>float farray[] = { 1, 2, 3, 4, 5, 6, 7 };
>
> sizeof(sizer_func(farray)));

Note that this should be
sizeof(sizer_func(farray).c);
See previous posts for an explanation why.


>In what ways is it better than sizeof(farray) / sizeof (farray[0]); ?
>
>I know that the original posting asked for template-only solution.
>There may be some practical reason for that ?

This "sizer" method garauntees that farray is a builtin array rather
than an pointer. Suppose you accidentally did
float* farray=new float[7];
const int N1=sizeof(farray)/sizeof(*farray); // compile time error
const int N2=sizeof(sizer_func(farray).c); // compiles ok
The "sizer" method catches inadvertent errors.


--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Nathan Myers

unread,
Jul 27, 1998, 3:00:00 AM7/27/98
to
Chichiang Wan <wa...@cup.hp.com> wrote:
>The following code to compute the size of array is pretty impressive:
>
>template <size_t N> struct sizer { char c[N]; };
>template <typename T, size_t N> sizer<N> sizer_func(T (&)[N]);
> sizeof(sizer_func("abc)));

It's impressive, but it doesn't work. sizeof(struct sizer<N>) may
be larger than N. This one (credited to Siemel Naran):

template <typename T, size_t N> char (& sizer(T (&)[N]))[N];

double f[sizeof(sizer("abc"))];
double g[sizeof(sizer(f))];

is impressive and it does work.

> In what ways is it better than sizeof(farray) / sizeof (farray[0]); ?

You cannot accidentally pass to sizer a pointer. Also, it is
shorter to write and since you only mention the array once, it
is less prone to errors.

ka...@my-dejanews.com

unread,
Jul 28, 1998, 3:00:00 AM7/28/98
to
In article <35BA59...@cup.hp.com>,

Chichiang Wan <wa...@cup.hp.com> wrote:
> The following code to compute the size of array is pretty impressive:
>
> template <size_t N> struct sizer { char c[N]; };
> template <typename T, size_t N> sizer<N> sizer_func(T (&)[N]); //not
> defined
>
> int iarray[] = { 1, 2, 3, 4, 5, 6 };
> float farray[] = { 1, 2, 3, 4, 5, 6, 7 };
>
> sizeof(sizer_func(farray)));
>
> In what ways is it better than sizeof(farray) / sizeof (farray[0]); ?

void
f( int a[ 10 ] )
{
cout << sizeof( a ) / sizeof( a[ 0 ] ) ;
}

The template solution will fail to compile; your solution will give a
wrong answer.

Obviously, the wrong answer is particularly bothersome when the results
are used to size a second array -- with any (bad) luck, the program
will still work most of the time.

--
James Kanze +33 (0)1 39 23 84 71 mailto: ka...@gabi-soft.fr
+49 (0)69 66 45 33 10 mailto: jka...@otelo.ibmmail.com
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orientée objet --
-- Beratung in objektorientierter Datenverarbeitung

-----== Posted via Deja News, The Leader in Internet Discussion ==-----


http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Paul D. DeRocco

unread,
Aug 1, 1998, 3:00:00 AM8/1/98
to
Siemel Naran wrote:
>
> >template <size_t N> struct sizer { char c[N]; };
> >template <typename T, size_t N> sizer<N> sizer_func(T (&)[N]); //not
> >defined
> >
> >int iarray[] = { 1, 2, 3, 4, 5, 6 };
> >float farray[] = { 1, 2, 3, 4, 5, 6, 7 };
>
> sizeof(sizer_func(farray).c);

Nathan Myers wrote:
>
> It's impressive, but it doesn't work. sizeof(struct sizer<N>) may
> be larger than N. This one (credited to Siemel Naran):
>
> template <typename T, size_t N> char (& sizer(T (&)[N]))[N];
> double f[sizeof(sizer("abc"))];
> double g[sizeof(sizer(f))];
>
> is impressive and it does work.

The Borland 5.01 compiler complains that it can't find a match for
'sizer_func(int*)' or 'sizer(char*)' or whatever. If I remove either the
T or N template parameter, it still fails to match. Only if I define an
explicit function, rather than a template, will it match. Is this just a
compiler bug? Has anyone found a way to make Borland match a template
function taking a parameter in the form 'T(&)[N]'? Or even 'T[N]'?

--

Ciao,
Paul

0 new messages