Why constexpr template functions would work?

Hi guys, I had this question thrust into my head, why constexpr template functions would work? As shown in the code below, it is a constexpr template function which returns the size of a given array of unknown type.

1
2
3
4
5
6
#include <iostream>
using namespace std;
template<typename T, const int a> constexpr const int f(T (&x)[a])
{
    return a;
}  Put the code you need help with here.


As far as I am concerned, constexpr functions are ones that can be evaluated at compile time, but template functions, no matter how I look at them, could not be the kind of functions that can be evaluated at compile time. And my reason is that the compiler only generates the code for a template function when it first meets one that is being used. For example, when I first defined the template function above, the compiler would not possibly know what type of T and what value of a I was going feed to this function, so it could not generate the function of the template, but then if in the main function, I had code like
1
2
3
int main()
int arr[3] = {1, 2, 3};
cout << f(arr];

then, the compiler would generate a corresponding version of the template function for this specific type of array.
And this mechanism seems much like what I learned about dynamic binding used with inherited classes, and I know that for dynamic binding, virtual functions are chosen to be used at runtime, so I conjecture that the template functions doing their instantiation at runtime as well, which would contradict with constexpr function being evaluated at compile time.
Templates are instantiated at compile-time.

1
2
3
4
5
6
7
8
9
10
11
template < typename T > int foo( T arg ) { return arg % 10 ; }

void bar( bool f ) // note: bar is never called
{
    if(f) foo(25) ; // fine: instantiate int foo(int)
    
    else foo(2.5) ; // *** compile-time error instantiating int foo(double) 
                    // invalid type of operand double for arg % 10
}

int main() {}

http://coliru.stacked-crooked.com/a/e1f124180b45b466
Just a little addition to what JLBorges has said, built-in array and stl arrays both have their sizes known at compile-time( forgetting gcc's extension for VLA atm ). So if you have int a [] { 1, 3, 6, 8 };, the compiler knows what size a has, therefore when you call a function with a signature like this:
1
2
template< typename Type, size_t N >
void func( Type (&a) [N] );


The compiler already knows what N is at compile time, so if you place a call to func with any 1D built-in array type, the compiler instantiate it at compile-time, not at runtime because all the information needed for the instantiation is available.

Therefore it would work as a constexpr.
Thanks for your replies. Really appreciate it!
Topic archived. No new replies allowed.