7 Expressions [expr]

7.7 Constant evaluation [expr.const]

7.7.6 Reflection [expr.const.reflect]

The evaluation of an expression can introduce one or more injected declarations.
The evaluation is said to produce the declarations.
[Note 1: 
An invocation of the library function template std​::​meta​::​define_aggregate produces an injected declaration ([meta.reflection.define.aggregate]).
— end note]
Each such declaration has
[Note 2: 
Special rules concerning reachability apply to synthesized points ([module.reach]).
— end note]
[Note 3: 
The program is ill-formed if injected declarations with different characteristic sequences define the same entity in different translation units ([basic.def.odr]).
— end note]
A member of an entity defined by an injected declaration shall not have a name reserved to the implementation ([lex.name]); no diagnostic is required.
Let C be a consteval-block-declaration, the evaluation of whose corresponding expression produces an injected declaration for an entity E.
The program is ill-formed if either
  • C is enclosed by a scope associated with E or
  • letting P be a point whose immediate scope is that to which E belongs, there is a function parameter scope or class scope that encloses exactly one of C or P.
[Example 1: struct S0 { consteval { std::meta::define_aggregate(^^S0, {}); // error: scope associated with S0 encloses the consteval block } }; struct S1; consteval { std::meta::define_aggregate(^^S1, {}); } // OK template <std::meta::info R> consteval void tfn1() { std::meta::define_aggregate(R, {}); } struct S2; consteval { tfn1<^^S2>(); } // OK template <std::meta::info R> consteval void tfn2() { consteval { std::meta::define_aggregate(R, {}); } } struct S3; consteval { tfn2<^^S3>(); } // error: function parameter scope of tfn2<^^S3> intervenes between the declaration of S3 // and the consteval block that produces the injected declaration template <typename> struct TCls { struct S4; static void sfn() requires ([] { consteval { std::meta::define_aggregate(^^S4, {}); } return true; }()) { } }; consteval { TCls<void>::sfn(); } // error: TCls<void>​::​S4 is not enclosed by requires-clause lambda struct S5; struct Cls { consteval { std::meta::define_aggregate(^^S5, {}); } // error: S5 is not enclosed by class Cls }; struct S6; consteval { // #1 struct S7; // local class std::meta::define_aggregate(^^S7, {}); // error: consteval block #1 does not enclose itself, // but encloses S7 struct S8; // local class consteval { // #2 std::meta::define_aggregate(^^S6, {}); // error: consteval block #1 encloses // consteval block #2 but not S6 std::meta::define_aggregate(^^S8, {}); // OK, consteval block #1 encloses both #2 and S8 } } — end example]
The evaluation context is a set of program points that determines the behavior of certain functions used for reflection ([meta.reflection]).
During the evaluation V of an expression E as a core constant expression, the evaluation context of an evaluation X ([intro.execution]) consists of the following points:
  • The program point , where L is the point at which E appears, and where , for a point P, is a point R determined as follows:
    • If a potentially-evaluated subexpression ([intro.execution]) of a default member initializer I appears at P, and a (possibly aggregate) initialization during V is using I, then R is where Q is the point at which that initialization appears.
    • Otherwise, if a potentially-evaluated subexpression of a default argument ([dcl.fct.default]) appears at P, and an invocation of a function ([expr.call]) during V is using that default argument, then R is where Q is the point at which that invocation appears.
    • Otherwise, R is P.
  • Each synthesized point corresponding to an injected declaration produced by any evaluation sequenced before X ([intro.execution]).