By combing the FDIS I have found three places that specify where a constexpr expression must be evaluated during translation.
Section 3.6.2 Initialization of non-local variables, paragraph 2 says if an object with static or thread local storage duration is initialized with a constexpr
constructor then the constructor is evaluated during translation:
Constant initialization is performed:
- if an object with static or thread storage duration is initialized by a constructor call, if the constructor is a
constexpr
constructor, if all constructor arguments are constant expressions (including conversions), and if, after function invocation substitution (7.1.5), every constructor call and full-expression in the mem-initializers is a constant expression;
Section 7.1.5 The constexpr specifier, paragraph 9 says if an object declaration includes the constexpr
specifier, that object is evaluated during translation (i.e., is a literal):
A constexpr
specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized. If it is initialized by a constructor call, that call shall be a constant expression (5.19). Otherwise, every full-expression that appears in its initializer shall be a constant expression. Each implicit conversion used in converting the initializer expressions and each constructor call used for the initialization shall be one of those allowed in a constant expression (5.19).
I’ve heard people argue that this paragraph leaves room for an implementation to postpone the initialization until runtime unless the effect can be detected during translation due to, say, a static_assert
. That is probably not an accurate view because whether a value is initialized during translation is, under some circumstances, observable. This view is reinforced by Section 5.19 Constant expressions paragraph 4:
[ Note: Although in some contexts constant expressions must be evaluated during program translation, others may be evaluated during program execution. Since this International Standard imposes no restrictions on the accuracy of floating-point operations, it is unspecified whether the evaluation of a floating-point expression during translation yields the same result as the evaluation of the same expression (or the same operations on the same values) during program execution... — end note ]
Section 9.4.2 Static data members, paragraph 3 says if a const static data member of literal type is initialized by a constexpr function or constructor, then that function or constructor must be evaluated during translation:
If a static data member is of const literal type, its declaration in the class definition can specify a brace-orequal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. A static data member of literal type can be declared in the class definition with the constexpr
specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. — end note ]
Interestingly, I did not find anything in the FDIS that required a constexpr
expression to be evaluated if its result is used as an array dimension. I'm quite sure the standard committee expects that to be the case. But I also could have missed that in my search.
Outside of those circumstances the C++11 standard allows computations in constexpr functions and constructors to be performed during translation. But it does not require it. The computations could occur at runtime. Which computations the compiler performs during translation are, to a certain extent, a quality of implementation question.
In all three of the situations I located, the trigger for translation-time evaluation is based on the requirements of the target using the result of the constexpr
call. Whether or not the arguments to the constexpr
function are literal is never considered (although it is a pre-requisite for valid evaluation).
So, to get to the real point of this, it appears that constexpr
evaluation during translation is triggered by:
- The implied object argument during overload resolution (Section 13.3.1 Paragraph 3) is either constexpr or requires a literal.
I hope that's helpful to someone besides me. Thanks to everyone who contributed.