SOLUTION: compile time array size using type only

  • Follow


Hi

here is the way for finding array size using type only

////////
  template<class T> class cx_array_length {
    template <class T, unsigned N> static inline const char
(&_bounds_fn(const T (&)[N]))[N];
    static const T * _arr;
  public:
    enum { value = sizeof(_bounds_fn(*_arr)) }; };


int length = cx_array_length<char[3]>::value;

//////////


the question is: is the compiler is smart enough not to put "_arr" into
the compiled object?

if you have better solutions/any ideas please share

regards, dmitry


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply dmitry.sychov (14) 9/7/2006 6:29:38 PM

"dmitry.sychov@mail.ru" <dmitry.sychov@mail.ru> writes:

> here is the way for finding array size using type only
>
> ////////
>   template<class T> class cx_array_length {
>     template <class T, unsigned N> static inline const char
> (&_bounds_fn(const T (&)[N]))[N];
>     static const T * _arr;
>   public:
>     enum { value = sizeof(_bounds_fn(*_arr)) }; };
>
>
> int length = cx_array_length<char[3]>::value;
>
> //////////
>
>
> the question is: is the compiler is smart enough not to put "_arr"
> into the compiled object?
>
> if you have better solutions/any ideas please share

What about:

template <typename T>
class cx_array_length
{
    enum
    {
      value = 1
    };
};

template <typename T, unsigned N>
struct cx_array_length<T[N]>
{
    enum
    {
      value = N
    };
};


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Thomas 9/7/2006 11:55:50 PM


* dmitry.sychov@mail.ru:
> 
> here is the way for finding array size using type only
> 
> ////////
>   template<class T> class cx_array_length {
>     template <class T, unsigned N> static inline const char

It would be a good idea to use std::size_t instead of unsigned here.

Also, 'inline' is superfluous.


> (&_bounds_fn(const T (&)[N]))[N];
>     static const T * _arr;
>   public:
>     enum { value = sizeof(_bounds_fn(*_arr)) }; };
> 
> 
> int length = cx_array_length<char[3]>::value;
> 
> //////////
> 
> 
> the question is: is the compiler is smart enough not to put "_arr" into
> the compiled object?

The number of tails a dog has depends on the dog, and is not mentioned 
in the Holy Standard. ;-)


> if you have better solutions/any ideas please share

     template< typename T > T const& aCompileTimeValueOf();  // No impl.

     typedef SomeType X[1234];
     std::size_t const length = N_ELEMENTS( aCompileTimeValueOf<X>() );

where N_ELEMENTS is any strictly compile time argument evaluation 
number-of-elements-in-array macro.

Since you addressed the "using type only" aspect you're probably aware 
of the techniques available when you have an actual array instance at 
hand, i.e. how N_ELEMENTS could be implemented, but for those who aren't 
familiar with this, see <url: 
http://home.no.net/dubjai/win32cpptut/special/pointers/array_size.doc.pdf> 
(which perhaps should be updated with Dmitry's technique/aspect).

-- 
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Alf 9/7/2006 11:57:21 PM

dmitry.sychov@mail.ru wrote:
> Hi
>
> here is the way for finding array size using type only
>
> ////////
>   template<class T> class cx_array_length {
>     template <class T, unsigned N> static inline const char
> (&_bounds_fn(const T (&)[N]))[N];
>     static const T * _arr;
>   public:
>     enum { value = sizeof(_bounds_fn(*_arr)) }; };
>
>
> int length = cx_array_length<char[3]>::value;
>
> //////////
>
>
> the question is: is the compiler is smart enough not to put "_arr" into
> the compiled object?

Since _arr is a static member, you are going to need to declare it in a
translation unit somewhere, and space will be allocated for it once,
which isn't such a big deal.

> if you have better solutions/any ideas please share

you can use the size of an array as a template parameter, so you could
do this much more directly with partial specialization, like this:

//define a general template for non-array types
template<typename InvalidType>
struct array_length {
     enum {value=0};
     //could also force a compile-time error here, with
BOOST_STATIC_ASSERT
};

//specialize it for array types
template<typename T, std::size_t N>
struct array_length<T[N]> {
     enum {value=N};
};

Now you have eg array_length<char[3]>::value = 3 as a compile time
constant.

-lewis


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply lhyatt 9/8/2006 12:03:05 AM

dmitry.sychov@mail.ru wrote:
> Hi
>
> here is the way for finding array size using type only
>
> ////////
>   template<class T> class cx_array_length {
>     template <class T, unsigned N> static inline const char
> (&_bounds_fn(const T (&)[N]))[N];
>     static const T * _arr;
>   public:
>     enum { value = sizeof(_bounds_fn(*_arr)) }; };
>
>
> int length = cx_array_length<char[3]>::value;
>
> //////////
>
>
> the question is: is the compiler is smart enough not to put "_arr" into
> the compiled object?
>

You don't need _arr - just cast 0 into a T * or T &  - it is not
evaluated inside the sizeof.  Some may argue that technically it
invokes undef behaviour, I'm not sure, but this is not a case where I'd
be concerned.


> if you have better solutions/any ideas please share
>

Thomas Maeder's looks better to me.  Quite elegant.  I only mention the
above stuff in case it helps elsewhere.

> regards, dmitry
> 
> 

Tony


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply gottlobfrege 9/8/2006 4:12:45 PM

Thomas Maeder wrote:
> "dmitry.sychov@mail.ru" <dmitry.sychov@mail.ru> writes:

> > here is the way for finding array size using type only

> > ////////
> >   template<class T> class cx_array_length {
> >     template <class T, unsigned N> static inline const char
> > (&_bounds_fn(const T (&)[N]))[N];
> >     static const T * _arr;
> >   public:
> >     enum { value = sizeof(_bounds_fn(*_arr)) }; };

> > int length = cx_array_length<char[3]>::value;

> > //////////

> > the question is: is the compiler is smart enough not to put
> > "_arr" into the compiled object?

If I understand the standard correctly, it isn't allowed to
instantiate the definition (and couldn't if it was, since you
haven't provided a definition) unless you use it.

> > if you have better solutions/any ideas please share

> What about:

> template <typename T>
> class cx_array_length
> {
>     enum
>     {
>       value = 1
>     };
> };

> template <typename T, unsigned N>
> struct cx_array_length<T[N]>
> {
>     enum
>     {
>       value = N
>     };
> };

But what's the point.  In both cases, in order to instantiate
the template, you have to specify the type, to specify the type,
you have to specify the size literally, and if you know the
size, it's much easier to write just:
    int length = 3 ;
than
    int length = cx_array_length< int[ 3 ] >::value ;
Or is there something here that I've missed?

We (you and I) recently did something more useful in
de.comp.lang.iso-c++, if I recall correctly:

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

which allows writing things like:

    double someArray[] = { 0.1, 0.2, 0.5, 1.0 } ;
    int length = sizeof( array_size( someArray ) ) ;

Obviously, the problem is even easier if you don't require a
constant integral expression.

--
James Kanze                                           GABI Software
Conseils en informatique orient�e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply kanze 9/8/2006 4:19:36 PM

lhyatt@princeton.edu wrote:
> dmitry.sychov@mail.ru wrote:

> > here is the way for finding array size using type only

> > ////////
> >   template<class T> class cx_array_length {
> >     template <class T, unsigned N> static inline const char
> > (&_bounds_fn(const T (&)[N]))[N];
> >     static const T * _arr;
> >   public:
> >     enum { value = sizeof(_bounds_fn(*_arr)) }; };

> > int length = cx_array_length<char[3]>::value;
> > //////////

> > the question is: is the compiler is smart enough not to put
> > "_arr" into the compiled object?

> Since _arr is a static member, you are going to need to
> declare it in a translation unit somewhere, and space will be
> allocated for it once, which isn't such a big deal.

Only if it is actually instantiated (the static member, not the
class).  And it should only be instatiated if it is actually
used, which it isn't.

--
James Kanze                                           GABI Software
Conseils en informatique orient�e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply kanze 9/8/2006 4:20:01 PM

kanze wrote:
>
> But what's the point.  In both cases, in order to instantiate
> the template, you have to specify the type, to specify the type,
> you have to specify the size literally, and if you know the
> size, it's much easier to write just:
>     int length = 3 ;
> than
>     int length = cx_array_length< int[ 3 ] >::value ;
> Or is there something here that I've missed?
>

I was wondering the same thing, but I suspect there may be times when
'int[3]' is only known as T - ie maybe this helps in other template
code?

Tony


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply gottlobfrege 9/12/2006 1:47:28 AM

kanze wrote:
,,,
>     template< typename N, size_t N >
>     char (&array_size( T (&array)[ N ] ))[ N ] ;
>
> which allows writing things like:
>
>     double someArray[] = { 0.1, 0.2, 0.5, 1.0 } ;
>     int length = sizeof( array_size( someArray ) ) ;
....

As an aside, I'm curious; could you not just have easily written:

  template< typename T, size_t N >
  size_t array_size( T (& array)[ N ] ) { return N; }

so that you could have written:

  double someArray[] = { 0.1, 0.2, 0.5, 1.0 } ;
  int length = array_size( someArray ) ;

thus directly obtaining the array size, rather than using sizeof?  I
have to assume there's a reason that I'm missing.  Either way, I think
that the technique is great; I'll have to remember it for future use.

John Moeller


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply John 9/12/2006 11:44:51 PM

John Moeller wrote:
> kanze wrote:
> ,,,
>>     template< typename N, size_t N >
>>     char (&array_size( T (&array)[ N ] ))[ N ] ;
>>
>> which allows writing things like:
>>
>>     double someArray[] = { 0.1, 0.2, 0.5, 1.0 } ;
>>     int length = sizeof( array_size( someArray ) ) ;
> ...
>
> As an aside, I'm curious; could you not just have easily written:
>
>  template< typename T, size_t N >
>  size_t array_size( T (& array)[ N ] ) { return N; }
>
> so that you could have written:
>
>  double someArray[] = { 0.1, 0.2, 0.5, 1.0 } ;
>  int length = array_size( someArray ) ;
>
> thus directly obtaining the array size, rather than using sizeof?  I
> have to assume there's a reason that I'm missing.  [..]

You're missing the fact that in James' code 'array_size' function
doesn't exist, it doesn't need to, since the expression inside 'sizeof'
is never evaluated.  In your code, however, 'length' is *dynamically*
initialised, by calling 'array_size' function.  In James' code, the
initialiser is compile-time constant expression.  In your code, it's
not.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Victor 9/13/2006 1:11:46 PM

John Moeller <fishcorn@gmail.com> wrote:
> kanze wrote:
> ,,,
> >     template< typename N, size_t N >
> >     char (&array_size( T (&array)[ N ] ))[ N ] ;
> >
> > which allows writing things like:
> >
> >     double someArray[] = { 0.1, 0.2, 0.5, 1.0 } ;
> >     int length = sizeof( array_size( someArray ) ) ;
> ...
>
> As an aside, I'm curious; could you not just have easily written:
>
>  template< typename T, size_t N >
>  size_t array_size( T (& array)[ N ] ) { return N; }
>
> so that you could have written:
>
>  double someArray[] = { 0.1, 0.2, 0.5, 1.0 } ;
>  int length = array_size( someArray ) ;
>
> thus directly obtaining the array size, rather than using sizeof?  I
> have to assume there's a reason that I'm missing. [...]

  Yours is a run-time solution, James' yields a compile-time
  constant.

  Schobi

-- 
SpamTrap@gmx.de is never read
I'm Schobi at suespammers dot org

"The sarcasm is mightier than the sword."
Eric Jarvis 



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Hendrik 9/13/2006 3:53:55 PM

John Moeller wrote:
> kanze wrote:

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

> > which allows writing things like:

> >     double someArray[] = { 0.1, 0.2, 0.5, 1.0 } ;
> >     int length = sizeof( array_size( someArray ) ) ;
> ...

> As an aside, I'm curious; could you not just have easily written:

>   template< typename T, size_t N >
>   size_t array_size( T (& array)[ N ] ) { return N; }

> so that you could have written:

>   double someArray[] = { 0.1, 0.2, 0.5, 1.0 } ;
>   int length = array_size( someArray ) ;

> thus directly obtaining the array size, rather than using sizeof?

In this case, yes, and in fact, that is the way it is done in my
own library.  The solution above came about as a result of a
discussion in de.comp.lang.iso_c++, where it was also desired to
be able to do something like:

    double secondArray[ sizeof( array_size( firstArray ) ) ] ;

That's what I meant when I said: "Obviously, the problem is even
easier if you don't require a constant integral expression."

(Unless I'm using static initialization, or the initialization
list is being used to determine the size, my arrays are always
std::vector.  Which means that I don't need a constant integral
expression.  So my code uses the simple forms:

    template< typename T, size_t N >
    size_t
    size( T (&array)[ N ] )
    {
        return N ;
    }

and the equivalent for begin() and end().  The names of the
functions being chosen, of course, to correspond to those of the
member functions in an STL container.)

--
James Kanze                                           GABI Software
Conseils en informatique orient�e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply kanze 9/13/2006 3:54:44 PM

On 13 Sep 2006 11:54:44 -0400, "kanze" <kanze@gabi-soft.fr> wrote:

>In this case, yes, and in fact, that is the way it is done in my
>own library.  The solution above came about as a result of a
>discussion in de.comp.lang.iso_c++, where it was also desired to
>be able to do something like:
>
>    double secondArray[ sizeof( array_size( firstArray ) ) ] ;

I don't doubt that you independently reinvented it, however I first
saw that tecnique in code by Dietmar Kuehl. IIRC it was code written
before year 2000.

I wrote a generalized version for multidimensional arrays which was
available in the boost vault. I plan to make an even more general
version, supporting tr1::array (and thus size==0), available under the
GPL. Of course the plain function is enough for most purposes. And
generalized constant expressions proposed by B. Stroustrup & G. Dos
Reis would give the best of both worlds.

--
Gennaro Prota

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Gennaro 9/13/2006 6:40:13 PM

Gennaro Prota wrote:
> On 13 Sep 2006 11:54:44 -0400, "kanze" <kanze@gabi-soft.fr> wrote:

> >In this case, yes, and in fact, that is the way it is done in
> >my own library.  The solution above came about as a result of
> >a discussion in de.comp.lang.iso_c++, where it was also
> >desired to be able to do something like:

> >    double secondArray[ sizeof( array_size( firstArray ) ) ] ;

> I don't doubt that you independently reinvented it, however I
> first saw that tecnique in code by Dietmar Kuehl. IIRC it was
> code written before year 2000.

It wouldn't surprise me.  I don't claim to have "invented" it.
I do think that anyone familiar with template meta-programming
today, even in it's simplest forms, would come up with it, given
the normal begin(), end() and size() functions (which I didn't
invent either, but heard about somewhere, although I don't
remember where).  It wouldn't surprise me either that Dietmar
invented it before 2000, when it wouldn't have been at all
evident; he's one of the most gifted programmers I know.

I mentionned the discussion in de.comp.lang.iso_c++ only because
I was responding to Thomas Maeder, who had mentionned it there
not more than a week ago.

--
James Kanze                                           GABI Software
Conseils en informatique orient�e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply kanze 9/14/2006 12:10:42 PM

John Moeller wrote:
> As an aside, I'm curious; could you not just have easily written:
>
>   template< typename T, size_t N >
>   size_t array_size( T (& array)[ N ] ) { return N; }
>
> so that you could have written:
>
>   double someArray[] = { 0.1, 0.2, 0.5, 1.0 } ;
>   int length = array_size( someArray ) ;
>

Can someone explain how that works?   I can't work out how the value
for template parameter N  is determined when all you pass to the
array_size function is the array ptr.

Thanks
Adrian.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Adrian 9/17/2006 10:58:45 AM

Adrian wrote:

> 
> John Moeller wrote:
> > As an aside, I'm curious; could you not just have easily written:
> > 
> >   template< typename T, size_t N >
> >   size_t array_size( T (& array)[ N ] ) { return N; }
> > 
> > so that you could have written:
> > 
> >   double someArray[] = { 0.1, 0.2, 0.5, 1.0 } ;
> >   int length = array_size( someArray ) ;
> > 
> 
> Can someone explain how that works?   I can't work out how the value
> for template parameter N  is determined when all you pass to the
> array_size function is the array ptr.
> 

You're not.   The function is being passed a reference to an array of
size N.

Of course, this assumes that the compiler has enough information, within
the scope where the function is called, to know it is working with an
array.    The following would result in an error;


size_t intermediary(double *v)
{
      return array_size(v);
}

int main()
{
      double someArray[] = { 0.1, 0.2, 0.5, 1.0 } ;
      size_t length = intermediary(someArray);

}

as the only information available to the compiler, at the point where
array_size() is called, is a pointer which includes no size information.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Bob 9/17/2006 7:06:56 PM

Adrian posted:

>>   template< typename T, size_t N >
>>   size_t array_size( T (& array)[ N ] ) { return N; }
>>
>>   double someArray[] = { 0.1, 0.2, 0.5, 1.0 } ;
>>   int length = array_size( someArray ) ;
>>
> 
> Can someone explain how that works?   I can't work out how the value
> for template parameter N  is determined when all you pass to the
> array_size function is the array ptr.


The word is "pointer".

The actual array is passed by reference -- it has no "decayed" to a pointer
to its first element. While you are correct that there's an implicit
conversion from "int[N]" to "int*", it will only take place if there's a
reason. In this context, there's no reason for the conversion to take place
because an array _can_ be passed by reference.

-- 

Frederick Gotham

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Frederick 9/17/2006 7:07:56 PM

Adrian wrote:
> John Moeller wrote:
>> As an aside, I'm curious; could you not just have easily written:
>>
>>   template< typename T, size_t N >
>>   size_t array_size( T (& array)[ N ] ) { return N; }
>>
>> so that you could have written:
>>
>>   double someArray[] = { 0.1, 0.2, 0.5, 1.0 } ;
>>   int length = array_size( someArray ) ;
>>
> 
> Can someone explain how that works?   I can't work out how the value
> for template parameter N  is determined when all you pass to the
> array_size function is the array ptr.

No pointer is passed; a reference to the array is passed,
though this could also work if a pointer to the array was
passed (as in "&someArray").  Passing a reference just
gives a more natural syntax.  Arrays do not "decay" to
pointers to their first element when passed by reference
(or in a number of other situations).

-- James

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply James 9/17/2006 7:08:24 PM

"Adrian" <borg@swirve.com> writes:
>>   template< typename T, size_t N >
>>   size_t array_size( T (& array)[ N ] ) { return N; }
>>
>> so that you could have written:
>>
>>   double someArray[] = { 0.1, 0.2, 0.5, 1.0 } ;
>>   int length = array_size( someArray ) ;
>
> Can someone explain how that works?   I can't work out how the value
> for template parameter N  is determined when all you pass to the
> array_size function is the array ptr.

You don't pass it the "array ptr". The array is passed by
reference.

The type of the array parameter is "reference to array of N objects of
type T". When someArray is passed, the compiler determines N and T so
that they fit.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Thomas 9/18/2006 7:38:38 PM

18 Replies
246 Views

(page loaded in 0.25 seconds)

Similiar Articles:


















7/22/2012 7:25:21 AM


Reply: