7 Expressions [expr]

7.6 Compound expressions [expr.compound]

7.6.2 Unary expressions [expr.unary]

7.6.2.10 The reflection operator [expr.reflect]

The unary ^^ operator, called the reflection operator, yields a prvalue of type std​::​meta​::​info ([basic.fundamental]).
[Note 1: 
This document places no restriction on representing, by reflections, constructs not described by this document or using the names of such constructs as operands of reflect-expressions.
— end note]
The component names of a reflection-name are those of its nested-name-specifier (if any) and its identifier.
The terminal name of a reflection-name of the form nested-name-specifier template identifier shall denote a template.
A reflect-expression is parsed as the longest possible sequence of tokens that could syntactically form a reflect-expression.
An unparenthesized reflect-expression that represents a template shall not be followed by <.
[Example 1: static_assert(std::meta::is_type(^^int())); // ^^ applies to the type-id int() template<bool>struct X {}; consteval bool operator<(std::meta::info, X<false>) { return false; } consteval void g(std::meta::info r, X<false> xv) { r == ^^int && true; // error: ^^ applies to the type-id int&& r == ^^int & true; // error: ^^ applies to the type-id int& r == (^^int) && true; // OK r == ^^int &&&& true; // error: int &&&& is not a valid type-id ^^X < xv; // error: reflect-expression that represents a template is followed by < (^^X) < xv; // OK ^^X<true> < xv; // OK } — end example]
A reflect-expression of the form ^^​::​ represents the global namespace.
If a reflect-expression R matches the form ^^reflection-name, it is interpreted as such; the identifier is looked up and the representation of R is determined as follows:
  • If lookup finds a declaration that replaced a using-declarator during a single search ([basic.lookup.general], [namespace.udecl]), R is ill-formed.
    [Example 2: struct A { struct S {}; }; struct B : A { using A::S; }; constexpr std::meta::info r1 = ^^B::S; // error: A​::​S found through using-declarator struct C : virtual B { struct S {}; }; struct D : virtual B, C {}; D::S s; // OK, names C​::​S per [class.member.lookup] constexpr std::meta::info r2 = ^^D::S; // OK, result C​::​S not found through using-declarator — end example]
  • Otherwise, if lookup finds a namespace alias ([namespace.alias]), R represents that namespace alias.
    For any other namespace-name, R represents the denoted namespace.
  • Otherwise, if lookup finds a namespace ([namespace.alias]), R represents that namespace.
  • Otherwise, if lookup finds a concept ([temp.concept]), R represents the denoted concept.
  • Otherwise, if lookup finds a template ([temp.names]), the representation of R is determined as follows:
    • If lookup finds an injected-class-name ([class.pre]), then:
    • Otherwise, if lookup finds an overload set, that overload set shall contain only declarations of a unique function template F; R represents F.
    • Otherwise, if lookup finds a class template, variable template, or alias template, R represents that template.
      [Note 2: 
      Lookup never finds a partial or explicit specialization.
      — end note]
  • Otherwise, if lookup finds a type alias A, R represents the underlying entity of A if A was introduced by the declaration of a template parameter; otherwise, R represents A.
  • Otherwise, if lookup finds a class or an enumeration, R represents the denoted type.
  • Otherwise, if lookup finds a class member of an anonymous union ([class.union.anon]), R represents that class member.
  • Otherwise, the reflection-name shall be an id-expression I and R is ^^I (see below).
A reflect-expression R of the form ^^type-id represents an entity determined as follows:
A reflect-expression R of the form ^^id-expression represents an entity determined as follows:
The id-expression of a reflect-expression is an unevaluated operand ([expr.context]).
[Example 3: template<typename T> void fn() requires (^^T != ^^int); template<typename T> void fn() requires (^^T == ^^int); template<typename T> void fn() requires (sizeof(T) == sizeof(int)); constexpr std::meta::info a = ^^fn<char>; // OK constexpr std::meta::info b = ^^fn<int>; // error: ambiguous constexpr std::meta::info c = ^^std::vector; // OK template<typename T> struct S { static constexpr std::meta::info r = ^^T; using type = T; }; static_assert(S<int>::r == ^^int); static_assert(^^S<int>::type != ^^int); typedef struct X {} Y; typedef struct Z {} Z; constexpr std::meta::info e = ^^Y; // OK, represents the type alias Y constexpr std::meta::info f = ^^Z; // OK, represents the type alias Z, not the type ([basic.lookup.general]) — end example]