7 Expressions [expr]

7.7 Constant evaluation [expr.const]

7.7.4 Constant initialization [expr.const.init]

The constituent values and constituent references of a variable x are defined as follows:
  • If x declares an object, the constituent values and references of that object ([intro.object]) are constituent values and references of x.
  • If x declares a reference, that reference is a constituent reference of x.
For any constituent reference r of a variable x, if r is bound to a temporary object or subobject thereof whose lifetime is extended to that of r, the constituent values and references of that temporary object are also constituent values and references of x, recursively.
An object o is constexpr-referenceable from a point P if
  • o has static storage duration, or
  • o has automatic storage duration, and, letting v denote
    • the variable corresponding to o's complete object or
    • the variable to whose lifetime that of o is extended,
    the smallest scope enclosing v and the smallest scope enclosing P that are neither are the same function parameter scope.
[Example 1: struct A { int m; const int& r; }; void f() { static int sx; thread_local int tx; // tx is never constexpr-referenceable int ax; A aa = {1, 2}; static A sa = {3, 4}; // The objects sx, ax, and aa.m, sa.m, and the temporaries to which aa.r and sa.r are bound, are constexpr-referenceable. auto lambda = [] { int ay; // The objects sx, sa.m, and ay (but not ax or aa), and the // temporary to which sa.r is bound, are constexpr-referenceable. }; } — end example]
An object or reference x is constexpr-representable at a point P if, for each constituent value of x that points to or past an object o, and for each constituent reference of x that refers to an object o, o is constexpr-referenceable from P.
A variable v is constant-initializable if
  • the full-expression of its initialization is a constant expression when interpreted as a constant-expression with all contract assertions using the ignore evaluation semantic ([basic.contract.eval]),
    [Note 1: 
    Within this evaluation, std​::​is_constant_evaluated() ([meta.const.eval]) returns true.
    — end note]
    [Note 2: 
    The initialization, when evaluated, can still evaluate contract assertions with other evaluation semantics, resulting in a diagnostic or ill-formed program if a contract violation occurs.
    — end note]
  • immediately after the initializing declaration of v, the object or reference x declared by v is constexpr-representable, and
  • if x has static or thread storage duration, x is constexpr-representable at the nearest point whose immediate scope is a namespace scope that follows the initializing declaration of v.
A constant-initializable variable is constant-initialized if either it has an initializer or its type is const-default-constructible ([dcl.init.general]).
[Example 2: void f() { int ax = 0; // ax is constant-initialized thread_local int tx = 0; // tx is constant-initialized static int sx; // sx is not constant-initialized static int& rss = sx; // rss is constant-initialized static int& rst = tx; // rst is not constant-initialized static int& rsa = ax; // rsa is not constant-initialized thread_local int& rts = sx; // rts is constant-initialized thread_local int& rtt = tx; // rtt is not constant-initialized thread_local int& rta = ax; // rta is not constant-initialized int& ras = sx; // ras is constant-initialized int& rat = tx; // rat is not constant-initialized int& raa = ax; // raa is constant-initialized } — end example]
A variable is potentially-constant if it is constexpr or it has reference or non-volatile const-qualified integral or enumeration type.
A constant-initialized potentially-constant variable V is usable in constant expressions at a point P if V's initializing declaration D is reachable from P and
  • V is constexpr,
  • V is not initialized to a TU-local value, or
  • P is in the same translation unit as D.
An object or reference is potentially usable in constant expressions at point P if it is
  • the object or reference declared by a variable that is usable in constant expressions at P,
  • a temporary object of non-volatile const-qualified literal type whose lifetime is extended ([class.temporary]) to that of a variable that is usable in constant expressions at P,
  • a template parameter object,
  • a string literal object,
  • a non-mutable subobject of any of the above, or
  • a reference member of any of the above.
An object or reference is usable in constant expressions at point P if it is an object or reference that is potentially usable in constant expressions at P and is constexpr-representable at P.
[Example 3: struct A { int* const & r; }; void f(int x) { constexpr A a = {&x}; static_assert(a.r == &x); // OK [&] { static_assert(a.r != nullptr); // error: a.r is not usable in constant expressions at this point }(); } — end example]