7 Expressions [expr]

7.7 Constant evaluation [expr.const]

7.7.3 Constant expressions [expr.const.const]

A constant expression is either
  • a glvalue core constant expression E for which
    • E refers to a non-immediate function,
    • E designates an object o, and if the complete object of o is of consteval-only type then so is E,
      [Example 1: struct Base { }; struct Derived : Base { std::meta::info r; }; consteval const Base& fn(const Derived& derived) { return derived; } constexpr Derived obj{.r=^^::}; // OK constexpr const Derived& d = obj; // OK constexpr const Base& b = fn(obj); // error: not a constant expression because Derived // is a consteval-only type but Base is not. — end example]
    or
  • a prvalue core constant expression whose result object ([basic.lval]) satisfies the following constraints:
    • each constituent reference refers to an object or a non-immediate function,
    • no constituent value of scalar type is an indeterminate or erroneous value ([basic.indet]),
    • no constituent value of pointer type is a pointer to an immediate function or an invalid pointer value ([basic.compound]),
    • no constituent value of pointer-to-member type designates an immediate function, and
    • unless the value is of consteval-only type,
      • no constituent value of pointer-to-member type points to a direct member of a consteval-only class type,
      • no constituent value of pointer type points to or past an object whose complete object is of consteval-only type, and
      • no constituent reference refers to an object whose complete object is of consteval-only type.
[Note 1: 
A glvalue core constant expression that either refers to or points to an unspecified object is not a constant expression.
— end note]
[Example 2: consteval int f() { return 42; } consteval auto g() { return f; } consteval int h(int (*p)() = g()) { return p(); } constexpr int r = h(); // OK constexpr auto e = g(); // error: a pointer to an immediate function is // not a permitted result of a constant expression struct S { int x; constexpr S() {} }; int i() { constexpr S s; // error: s.x has erroneous value } — 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 2: 
Such expressions can be used as bit-field lengths ([class.bit]), as enumerator initializers if the underlying type is not fixed ([dcl.enum]), and as alignments.
— 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 ([conv]) to an integral or unscoped enumeration type and the selected conversion function shall be constexpr.
[Example 3: struct A { constexpr A(int i) : val(i) { } constexpr operator int() const { return val; } constexpr operator long() const { return 42; } private: int val; }; constexpr A a = alignof(int); alignas(a) int n; // error: ambiguous conversion struct B { int n : a; }; // error: ambiguous conversion — end example]
A converted constant expression of type T is an expression, implicitly converted to type T, where the converted expression is a constant expression and the implicit conversion sequence contains only and where the reference binding (if any) binds directly.
[Note 3: 
Such expressions can 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]), as constant template arguments ([temp.arg]), and as the constant expression of a splice-specifier ([basic.splice]).
— end note]
A contextually converted constant expression of type bool is an expression, contextually converted to bool ([conv]), where the converted expression is a constant expression and the conversion sequence contains only the conversions above.