Question

Can someone please explain why the marked line below compiles fine:

template<typename T, int N>
constexpr
int get_size(T (&)[N])
{
    return N;
}

int main()
{
    int xs[10];
    constexpr int y = get_size(xs); // HERE.
    static_assert(10 == y, "wrong size");
}

Intuitively to me, get_size(xs) isn't a constant expression because xs itself isn't so I don't understand why it works.

Was it helpful?

Solution

After the template function is instantiated your program becomes equivalent to the following:

constexpr
int get_size(int (&)[10])
{
    return 10;
}

int main()
{
    int xs[10];
    constexpr int y = get_size(xs); // HERE.
    static_assert(10 == y, "wrong size");
}

Then after function invocation substitution it becomes equivalent to the following:

int main()
{
    int xs[10];
    constexpr int y = 10; // HERE.
    static_assert(10 == y, "wrong size");
}

Function invocation substitution is described under 7.1.5 [dcl.constexpr]/5. Essentially parameters are replaces as if copy-initialized and then subsituted for occurences in the return expression. The return expression then likewise as-if copy-initializes the return value. The resulting expression then becomes the expression that is subsituted for the function call. Only after this is the expression considered if it satisfies the constraints on constant expressions placed by the context. (Note, a quality compiler can of course determine that the constexpr function can never be used successfully after any such operation, and can fail after encounting the function definition, but it doesn't have to)

Also note, just to confuse you this concept is removed in C++14 and replaced with a different concept for how constexpr functions are evaluated. Among other things you will be able to use if statements, for statements and local variables of literal type within constexpr functions.

OTHER TIPS

Your question and the comment:

I guess I'm confused why an automatic variable whose address isn't known can be passed by reference to a function used in a constant expression

When the compiler sees get_size(xs), it has already parsed the previous line which is int xs[10]; and thus knows the type and size of xs. There is nothing going to change at runtime, as far the type and the size is concerned — and these two are the information required by the compile in order to instantiate the function template, so it doesn't face any problem instantiating the function template, which in this case behaves as constexpr because everything is known at compile-time, which is why the static_assert doesn't fail.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top