5 Expressions [expr]

5.19 Constant expressions [expr.const]

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 is a core constant expression unless it involves one of the following as a potentially evaluated subexpression ([basic.def.odr]), but subexpressions of logical AND ([expr.log.and]), logical OR ([expr.log.or]), and conditional ([expr.cond]) operations that are not evaluated are not considered [ Note: An overloaded operator invokes a function. — end note ]:

  • this ([expr.prim]) unless it appears as the postfix-expression in a class member access expression, including the result of the implicit transformation in the body of a non-static member function ([class.mfct.non-static]);

  • an invocation of a function other than a constexpr constructor for a literal class or a constexpr function [ Note: Overload resolution ([over.match]) is applied as usual  — end note ];

  • an invocation of an undefined constexpr function or an undefined constexpr constructor outside the definition of a constexpr function or a constexpr constructor;

  • an invocation of a constexpr function with arguments that, when substituted by function invocation substitution ([dcl.constexpr]), do not produce a constant expression; [ Example:

    constexpr const int* addr(const int& ir) { return &ir; }  // OK
    static const int x = 5;
    constexpr const int* xp = addr(x);  // OK: (const int*)&(const int&)x is an
                                        // address constant expression
    constexpr const int* tp = addr(5);  // error, initializer for constexpr variable not a constant
                                        // expression; (const int*)&(const int&)5 is not a constant
                                        // expression because it takes the address of a temporary
    

     — end example ]

  • an invocation of a constexpr constructor with arguments that, when substituted by function invocation substitution ([dcl.constexpr]), do not produce all constant expressions for the constructor calls and full-expressions in the mem-initializers; [ 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 after substitution
    constexpr int w = A(false).m;       // error: initializer for m is
                                        // x, which is non-constant
    

     — end example ]

  • an invocation of a constexpr function or a constexpr constructor that would exceed the implementation-defined recursion limits (see Annex [implimits]);

  • a result that is not mathematically defined or not in the range of representable values for its type;

  • a lambda-expression ([expr.prim.lambda]);

  • an lvalue-to-rvalue conversion ([conv.lval]) unless it is applied to

    • a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression, or

    • a glvalue of literal type that refers to a non-volatile object defined with constexpr, or that refers to a sub-object of such an object, or

    • a glvalue of literal type that refers to a non-volatile temporary object whose lifetime has not ended, initialized with a constant expression;

  • an lvalue-to-rvalue conversion ([conv.lval]) 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, initialized with a constant expression;

  • a dynamic cast ([expr.dynamic.cast]);

  • a reinterpret_cast ([expr.reinterpret.cast]);

  • a pseudo-destructor call ([expr.pseudo]);

  • increment or decrement operations ([expr.post.incr], [expr.pre.incr]);

  • a typeid expression ([expr.typeid]) whose operand is of a polymorphic class type;

  • a new-expression ([expr.new]);

  • a delete-expression ([expr.delete]);

  • a subtraction ([expr.add]) where both operands are pointers;

  • a relational ([expr.rel]) or equality ([expr.eq]) operator where the result is unspecified;

  • an assignment or a compound assignment ([expr.ass]); or

  • a throw-expression ([except.throw]).

A literal constant expression is a prvalue core constant expression of literal type, but not pointer type. An integral constant expression is a literal constant expression of integral or unscoped enumeration type. [ 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]), as null pointer constants ([conv.ptr]), and as alignments ([dcl.align]).  — end note ] A converted constant expression of type T is a literal constant expression, implicitly converted to type T, where the implicit conversion (if any) is permitted in a literal 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 as case expressions ([stmt.switch]), as enumerator initializers if the underlying type is fixed ([dcl.enum]), and as integral or enumeration non-type template arguments ([temp.arg]).  — end note ] A reference constant expression is an lvalue core constant expression that designates an object with static storage duration or a function. An address constant expression is a prvalue core constant expression of pointer type that evaluates to the address of an object with static storage duration, to the address of a function, or to a null pointer value, or a prvalue core constant expression of type std::nullptr_t. Collectively, literal constant expressions, reference constant expressions, and address constant expressions are called constant expressions.

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.84Example:

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 class type shall have a single non-explicit conversion function to an integral or unscoped enumeration type and that conversion function shall be constexpr. [ Example:

struct A { 
  constexpr A(int i) : val(i) { } 
  constexpr operator int() { return val; } 
  constexpr operator long() { 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 

 — end example ]

Nonetheless, implementations are encouraged to provide consistent results, irrespective of whether the evaluation was actually performed during translation or during program execution.