How does this "size of array" template function work?

BobAlmond picture BobAlmond · Jul 30, 2010 · Viewed 48.8k times · Source

Can someone explain how this code works? I know that the purpose of this code is to get the length of an array, but I don't know how this code works:

template<typename T, int size>
int GetArrLength(T(&)[size]){return size;}

Answer

GManNickG picture GManNickG · Jul 30, 2010

First let's dissect the parameter, T(&)[size]. Read declarations from inside out, right to left, parenthesis group first: It's an unnamed parameter that is a reference to an array of size size of type T.

That is, it accepts a reference to any array, where the type and size of the array are template parameters.

If we call it as such:

int a[10];
GetArrLength(a);

The compiler will try to deduce the template parameters. For the parameter type to match what you're passing, T must be int and size must be 10 (making the parameter a reference to an array of 10 ints).

You then return that size, giving you the number of elements in an array.


There are two "problems" with this code. Firstly, sizes cannot be negative, so it doesn't make sense to use a signed type as the template parameter and return type. Rather, an unsigned type should be used; best would be std::size_t:

template<typename T, std::size_t Size>
std::size_t GetArrLength(T(&)[Size]) { return size; }

The second is that the result of this function is not a constant-expression, even though an array's size is. While that's fine in most situations, it would be better if we could get a constant-expression from it. That's where you end up with this solution:

template <std::size_t N>
struct type_of_size
{
    typedef char type[N];
};

template <typename T, std::size_t Size>
typename type_of_size<Size>::type& sizeof_array_helper(T(&)[Size]);

#define sizeof_array(pArray) sizeof(sizeof_array_helper(pArray))

This is used as such:

int a[10];
const std::size_t n = sizeof_array(a); // constant-expression!

It works by three things: the first is the same idea as above, that template parameters will be filled out giving you the array's size.

The second part is using that information to make a type with a specific size, hence the type_of_size helper. That part isn't strictly necessary, but I think it makes the code easier to read. A char[N] has a size equal to N, always, hence we can abuse that to "store" the size of the array...in the size of a type itself!

The third part is getting that size with sizeof. It doesn't actually evaluate anything, so we don't need a definition for the function. It simply says "If you were to do this...the size would be...". And the size is our "stored" size, in the char array.