4

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.

2
  • 3
    The size of xs is a compile time constant, which is what the function template gets for you. Commented Oct 16, 2013 at 10:33
  • @juanchopanza 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. Commented Oct 16, 2013 at 10:36

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

4 Comments

I think I just came to a slightly related revelation: does that mean you can do "non-constant-expression" things inside of a constexpr function and it is fine as long as its not actually executed. I.e. why constexpr int x = (false ? std::puts("Hello") : 0, 0); is also fine and why throwing causes a compile-time error (I thought throw was handled specially but it might not be).
@Simple: false ? std::puts("Hello") : 0 is a constant expression. See 5.19 Constant expressions [expr.const]. The LHS is not evaluated and so not considered in a conditional expression.
This is cool. This means you could assert in a constexpr function depending on how the macro is implemented (or you could write your own like #define ASSERT(x) ((x) ? void() : ::std::abort())) and initialisating a constexpr variable would give you a compile error and otherwise get a runtime error.
Looks much better than the other answer, which was too much common sense and too few standard proof for me.
2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.