>And could you explain exactly HOW the template is doing that?
Sure. First, as I'm sure you know, the sizeof operator doesn't evaluate its operand. sizeof simply calculates the size of the type of the end result of the operand. If the operand is an expression, sizeof gives you the size of the type of the result of the expression. If the operand is a function call, sizeof gives you the size of the type of the return value.
So I built on the fact that you can return a reference to an array, and sizeof will give you the size of the array in bytes:
#include <iostream>
char (&foo())[5];
int main()
{
std::cout<< sizeof foo() <<'\n';
}
If you pass the size of the array as a template argument, you don't need to specify it as a constant as I did in the example above, so you can find the size of an array of char of any size by making the function a template:
#include <iostream>
template <int N>
char (&foo())[N];
int main()
{
std::cout<< sizeof foo<5>() <<'\n';
}
Of course, that's damn near useless because you still have to specify the size, and that defeats the purpose of the solution I wanted. So the size needs to be implicitly deduced through an argument to the function, and that means passing a reference to an array of the size we want:
#include <iostream>
template <int N>
char (&foo(char (&arg)[N]))[N];
int main()
{
char a[5];
std::cout<< sizeof foo(a) <<'\n';
}
Now, this still isn't very useful because the size in bytes of an array of char is the same as the number of elements because the size of a char is guaranteed to be 1. The trick here is to notice that the type of the argument is irrelevant; only the size matters, so you can change the type of the argument to the type of the array you plan to pass:
#include <iostream>
template <int N>
char (&foo(int (&arg)[N]))[N];
int main()
{
int a[5];
std::cout<< sizeof foo(a) <<'\n';
}
That still gives the correct size of 5, even for an array of integers, the size of which are guaranteed *not* to be 1. Now, if you deduce the type of the array argument through the template, you have a nice generic array size component:
#include <iostream>
template <typename T, int N>
char (&foo(T (&arg)[N]))[N];
int main()
{
int a[5];
std::cout<< sizeof foo(a) <<'\n';
}
Finally, to finish off the solution, the argument name isn't needed because this is only a function declaration and the name isn't used. Also, the name of the function template should reflect what we want to do with it. I chose to call the function "array" because "sizeof array(a)" makes all kinds of sense to me. It smoothly reads "take the size of the array a". So the final template is:
#include <iostream>
template <typename T, int N>
char (&array(T(&)[N]))[N];
int main()
{
int a[5];
std::cout<< sizeof array(a) <<'\n';
}