tags:

views:

175

answers:

3

Please consider this code:

template<typename T>
void f(T x) {
    std::cout << sizeof(T);
}

int array[27];
f(array);
f<typeof(array)>(array);

This will print

8 (or 4)
108

In the first case, the array obviously decays to a pointer and T becomes int*. In the second case, T is forced to int[27]. Is the order of decay/substitution implementation defined? Is there a more elegant way to force the type to int[27]? Besides using std::vector?

+1  A: 

Depending on your use case, you can work around that using references:

template<typename T>
void f(const T& x) {
    std::cout << sizeof(T);
}

char a[27];
f(a);

That prints 27, as desired.

Georg Fritzsche
Probably should use a const-reference, since you're not modifying T.
GMan
Right, just did the minimal changes needed to the OPs code.
Georg Fritzsche
+7  A: 

Use the reference type for the parameter

template<typename T> void f(const T& x) 
{
  std::cout << sizeof(T);
}

in which case the array type will not decay.

Similarly, you can also prevent decay in your original version of f if you explicitly specify the template agument T as a reference-to-array type

f<int (&)[27]>(array);

In your original code sample, forcing the argument T to have the array type (i.e. non-reference array type, by using typeof or by specifying the type explicitly), will not prevent array type decay. While T itself will stand for array type (as you observed), the parameter x will still be declared as a pointer and sizeof x will still evaluate to pointer size.

AndreyT
Yes, but I am using sizeof(T). Anyway, thanks for the fast answer :-)
drhirsch
+1  A: 

You can also use templates like the following:

template <typename T, std::size_t N>
inline std::size_t number_of_elements(T (&ary)[N]) {
    return N;
}

This little trick will cause compile errors if the function is used on a non-array type.

D.Shawley