Certain contexts require expressions that satisfy additional requirements as detailed in this sub-clause; other contexts have different semantics depending on whether or not an expression satisfies these requirements. Expressions that satisfy these requirements are called constant expressions. [ Note: Constant expressions can be evaluated during translation. — end note ]
constant-expression: conditional-expression
A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following expressions:
this ([expr.prim.general]), except in a constexpr function or a constexpr constructor that is being evaluated as part of e;
an invocation of a function other than a constexpr constructor for a literal class, a constexpr function, or an implicit invocation of a trivial destructor ([class.dtor]) [ Note: Overload resolution ([over.match]) is applied as usual — end note ];
an invocation of an undefined constexpr function or an undefined constexpr constructor;
an expression that would exceed the implementation-defined limits (see Annex [implimits]);
an operation that would have undefined behavior [ Note: including, for example, signed integer overflow (Clause [expr]), certain pointer arithmetic ([expr.add]), division by zero ([expr.mul]), or certain shift operations ([expr.shift]) — end note ];
an lvalue-to-rvalue conversion ([conv.lval]) unless it is applied to
a non-volatile glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression [ Note: a string literal ([lex.string]) corresponds to an array of such objects. — end note ], or
a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to a non-mutable sub-object of such an object, or
a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;
an lvalue-to-rvalue conversion ([conv.lval]) or modification ([expr.ass], [expr.post.incr], [expr.pre.incr]) that is applied to a glvalue that refers to a non-active member of a union or a subobject thereof;
an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
it is initialized with a constant expression or
it is a non-static data member of an object whose lifetime began within the evaluation of e;
in a lambda-expression, a reference to this or to a variable with automatic storage duration defined outside that lambda-expression, where the reference would be an odr-use ([basic.def.odr], [expr.prim.lambda]);
a conversion from type cv void * to a pointer-to-object type;
a dynamic cast ([expr.dynamic.cast]);
a reinterpret_cast ([expr.reinterpret.cast]);
a pseudo-destructor call ([expr.pseudo]);
modification of an object ([expr.ass], [expr.post.incr], [expr.pre.incr]) unless it is applied to a non-volatile lvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;
a typeid expression ([expr.typeid]) whose operand is a glvalue of a polymorphic class type;
a new-expression ([expr.new]);
a relational ([expr.rel]) or equality ([expr.eq]) operator where the result is unspecified; or
[ Example:
int x; // not constant struct A { constexpr A(bool b) : m(b?42:x) { } int m; }; constexpr int v = A(true).m; // OK: constructor call initializes // m with the value 42 constexpr int w = A(false).m; // error: initializer for m is // x, which is non-constant constexpr int f1(int k) { constexpr int x = k; // error: x is not initialized by a // constant expression because lifetime of k // began outside the initializer of x return x; } constexpr int f2(int k) { int x = k; // OK: not required to be a constant expression // because x is not constexpr return x; } constexpr int incr(int &n) { return ++n; } constexpr int g(int k) { constexpr int x = incr(k); // error: incr(k) is not a core constant // expression because lifetime of k // began outside the expression incr(k) return x; } constexpr int h(int k) { int x = incr(k); // OK: incr(k) is not required to be a core // constant expression return x; } constexpr int y = h(1); // OK: initializes y with the value 2 // h(1) is a core constant expression because // the lifetime of k begins inside h(1)
— end example ]
An integral constant expression is an expression of integral or unscoped enumeration type, implicitly converted to a prvalue, where the converted expression is a core constant expression. [ Note: Such expressions may be used as array bounds ([dcl.array], [expr.new]), as bit-field lengths ([class.bit]), as enumerator initializers if the underlying type is not fixed ([dcl.enum]), and as alignments ([dcl.align]). — end note ] A converted constant expression of type T is an expression, implicitly converted to a prvalue of type T, where the converted expression is a core constant expression and the implicit conversion sequence contains only user-defined conversions, lvalue-to-rvalue conversions ([conv.lval]), integral promotions ([conv.prom]), and integral conversions ([conv.integral]) other than narrowing conversions ([dcl.init.list]). [ Note: such expressions may be used in new expressions ([expr.new]), as case expressions ([stmt.switch]), as enumerator initializers if the underlying type is fixed ([dcl.enum]), as array bounds ([dcl.array]), and as integral or enumeration non-type template arguments ([temp.arg]). — end note ]
A constant expression is either a glvalue core constant expression whose value refers to an object with static storage duration or to a function, or a prvalue core constant expression whose value is an object where, for that object and its subobjects:
each non-static data member of reference type refers to an object with static storage duration or to a function, and
if the object or subobject is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object ([expr.add]), the address of a function, or a null pointer value.
[ Note: 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.87 [ Example:
bool f() { char array[1 + int(1 + 0.2 - 0.1 - 0.1)]; // Must be evaluated during translation int size = 1 + int(1 + 0.2 - 0.1 - 0.1); // May be evaluated at runtime return sizeof(array) == size; }
It is unspecified whether the value of f() will be true or false. — end example ] — end note ]
If an expression of literal class type is used in a context where an integral constant expression is required, then that expression is contextually implicitly converted (Clause [conv]) to an integral or unscoped enumeration type and the selected conversion function shall be constexpr. [ Example:
struct A { constexpr A(int i) : val(i) { } constexpr operator int() const { return val; } constexpr operator long() const { return 43; } private: int val; }; template<int> struct X { }; constexpr A a = 42; X<a> x; // OK: unique conversion to int int ary[a]; // error: ambiguous conversion
Nonetheless, implementations are encouraged to provide consistent results, irrespective of whether the evaluation was performed during translation and/or during program execution.