Topic: Templates and array type (was sizeof Template problem SOLVED!)


Author: jamshid@ses.com (Jamshid Afshar)
Date: Mon, 17 Jan 1994 00:11:01 GMT
Raw View
Redirected to comp.std.c++.

In article <1994Jan14.171518.14709@cronkite.ocis.temple.edu>,
Bruce Weiner <wizard@astro.ocis.temple.edu> wrote:
> For all you people who said it was IMPOSIBLE!!!~!!!!
> I think I have solved the Template for the sizeof Problem!!
>
>#include <iostream.h>
>#include <string.h>
>
>// Template seems to work correctly
>
>template <class T>
>int getsizeof(T (x)) {

In the body of this function you assume that getsizeof() is only
called with an address of an array, so `x' will have the type "pointer
to array".  Note thta your code will not compile if any other
parameter type is used (like int) and it will silently fail at
run-time if a pointer is passed.  Btw, Why the parens around `x'?

>   int tsize,size,sizex,sizex0;
>
>   tsize =  strlen( (char*)(x) ) + 1; // add 1 for the null character

What happens when the array pointed to by `x' does not have a 0 byte?
The call to strlen() will crash.

>   sizex =  sizeof( (x) ) ;
>   sizex0 = sizeof ( x[0] );
>   if (tsize == sizex0)
>      return size;

You never set `size' to anything, so why are you returning it?  I
assume you meant to return `tsize'.  Also, why do you think that if
tsize==sizex0 it must be a character array?  That's not true --
another array might just happen to have a zero byte at that particular
location.  Why are you even distinguishing character arrays?  What use
is sizeof(x) -- it's sizeof(pointer-to-array)?

>   // else item is not a character array!
>   size = sizex0 / sizex;
>   return size;
>};

If you don't mind passing the address of arrays and if you don't mind
that getsizeof() only works for arrays (neither of which was clear
from your last post), what's wrong with:

 template <class T>
 inline int getsizeof(T x) { return sizeof(*x)/sizeof((*x)[0]); }
 // assumes T is of type "pointer to array", returns number of
 // elements in array

 char name[] = "Bruce Weiner ?";
 int num[10];

 int main() {
    assert( getsizeof(&name) == sizeof(name)/sizeof(name[0]) );
    assert( getsizeof(&num) == sizeof(num)/sizeof(num[0]) );
    // extern double z[]; getsizeof(&z); -- compile-time error
    return 0;
 }

Amazingly, all the compilers I use which implement templates accept
this code (BC++ 3.1&4.0, Watcom C++, EDG, Cfront 3.0.2 and g++
2.5.5).

I hadn't thought of it before, but a version of getsizeof() taking a
reference to an array should work just as well as this one taking a
pointer to an array.  Unfortunately all my compilers except EDG have
bugs with references to arrays and/or with matching a template
function with an array type.

Watcom C++ and BC++ 3.1 fail to compile the following code.  g++ 2.5.5
compiles it but fails the assertion.

 int getsizeof(char (&x)[15]) { return sizeof(x)/sizeof(x[0]); }
 // note, this is NOT like a parameter `char x[15]'
 char name[] = "Bruce Weiner ?";
 int main() {
    assert( getsizeof(name) == sizeof(name)/sizeof(name[0]) );
    return 0;
 }

Although BC++ 4.0 and Cfront 3.0.2 accept code like this, they fail to
match function templates properly.  Since not even trivial conversions
are applied to match template functions I think the following code
should instantiate T with the type `int[10]' so that parameter `a' is
a reference to an array.  None of my compilers except EDG agree.  They
all instantiate T with the type `int*', which makes the call to f()
illegal since `a' is a non-const reference to an `int*'.

 typedef int Arr10[10];

 template<class T>
 void f( T& a ) {
     assert( sizeof(T) == sizeof(Arr10) );
     assert( sizeof(a[0]) == sizeof(int) );
 }

 Arr10 arr10;

 int main() {
     f( arr10 );  // all compilers except EDG fail here
     return 0;
 }

So, EDG makes the only C++ compiler in existence (unless maybe IBM C++
and DEC C++ get this right) that accepts the following code, which I
believe will not only be legal ANSI/ISO C++, but is now legal
according to the more restricted template rules in the ARM.

 template <class T>
 int getsizeof(T& x) { return sizeof(x)/sizeof(x[0]); }

 char name[] = "Bruce Weiner ?";
 int num[10];

 int main() {
    assert( getsizeof(name) == sizeof(name)/sizeof(name[0]) );
    assert( getsizeof(num) == sizeof(num)/sizeof(num[0]) );
    return 0;
 }

Jamshid Afshar
jamshid@ses.com