The basic parameter to the function says that you are passing in a reference to an unnamed array (the (&) part), which is of type T (the T part) and of size N (the [N] part). Since this information must be known at compile time, it means it only work for explicitly declared arrays that will never change size, i.e. something like int temp[50], however if you did something like pass the array in as a pointer, you loose the size information of the array and the code wont even compile. Thus in summary the value of N is derived from the size used in the array declaration.
This example shows the case where it works because the size (which is 50) of the array is known at compile time:
#include <iostream>
template<typename T, std::size_t N>
constexpr std::size_t arraySize(T (&)[N]) noexcept
{
return N; // and
}
int main()
{
int temp[50];
std::cout << "Array Size: " << arraySize(temp) << std::endl;
return 0;
}
This shows a broken example where the code wont compile because the size information has been lost as the pointer only stores the memory locations of the first element in the array and nothing relating to the size of the array.
#include <iostream>
template<typename T, std::size_t N>
constexpr std::size_t arraySize(T (&)[N]) noexcept
{
return N; // and
}
int main()
{
int temp[50];
int * temp1 = temp;
std::cout << "Array Size: " << arraySize(temp1) << std::endl;
return 0;
}
The function parameter don't have to be unnamed, i.e. it can be given a name though there is no point since it's not referenced inside the function. I.e:
template<typename T, std::size_t N>
constexpr std::size_t arraySize(T (&array)[N]) noexcept
{
return N; // and
}
And for good measure, since I rarely see arrays being passed in by reference, here is a short example of passing arrays by reference to functions.
#include <iostream>
// The size of the array.
#define ARRAY_SIZE 50
// Return the size of the array.
template<typename T, std::size_t N>
constexpr std::size_t gArraySize(T (&)[N]) noexcept
{
return N;
}
// Print the content of an array.
void gPrintArray(int (&temp)[ARRAY_SIZE])
{
// Print all the values.
for(auto i : temp)
{
std::cout << i << ",";
}
// Output a new line.
std::cout << std::endl;
}
int main()
{
// The temporary test array.
int temp[ARRAY_SIZE];
// Initialise the array.
for(int i = 0; i < ARRAY_SIZE; i++)
{
// Set the array value to it's index in the array.
temp[i] = i;
}
// Print the size of the array.
std::cout << "Array Size: " << gArraySize(temp) << std::endl;
// Print the array.
gPrintArray(temp);
return 0;
}
Of course, those of us who write firmware will not go through all this trouble just to get the size, we just straight use the ARRAY_SIZE definition to save precious clock cycles ;)