Reflexionsoperator (seit C++26)
Der unäre ^^ Operator, genannt Reflexionsoperator, liefert die Reflexion des gegebenen Sprachkonstrukts vom Typ std::meta::info.
Syntax
^^ ::
|
(1) | ||||||||
^^ Reflexionsname
|
(2) | ||||||||
^^ Typ-ID
|
(3) | ||||||||
^^ ID-Ausdruck
|
(4) | ||||||||
| Reflexionsname | - | ein Bezeichner, optional qualifiziert, optional unter Verwendung des Template-Disambiguators. Diese Form hat Vorrang vor Typ-ID und ID-Ausdruck |
| Typ-ID | - | eine Typ-ID |
| ID-Ausdruck | - | ein ID-Ausdruck |
Die längste Sequenz von Token, die syntaktisch den Operanden von ^^ bilden könnte, wird geparst. Wenn das Ergebnis ein Template darstellt, darf dem Ausdruck nicht direkt < folgen.
static_assert(std::meta::is_type(^^int())); // ^^int() represents the type int()
// not a function call to ^^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
}
Erklärung
^^:: repräsentiert den globalen Namensraum.^^reflection-name wird der Reflexionsname nachgeschlagen, und die Darstellung wird wie folgt bestimmt:
- Wenn die Suche eine Deklaration findet, die einen using-Deklarator ersetzt hat, ist der Ausdruck ungültig.
- Andernfalls, wenn die Suche einen Namensraumalias, Namensraum oder ein Konzept findet, repräsentiert das Ergebnis diese Entität.
- Andernfalls, wenn die Suche ein Template findet:
- Wenn die Suche einen eingefügten Klassennamen findet:
- Wenn der Template-Disambiguator vorhanden ist, repräsentiert das Ergebnis das Klassentemplate, das durch den eingefügten Klassennamen benannt wird.
- Andernfalls muss der eingefügte Klassenname, wenn er als Typname betrachtet wird, eindeutig sein (sonst ist der Ausdruck ungültig). Das Ergebnis repräsentiert den so benannten Typ.
- Andernfalls, wenn die Suche eine Überladungsmenge findet, muss diese Überladungsmenge nur Deklarationen eines eindeutigen Funktionstemplates enthalten. Das Ergebnis repräsentiert dieses Funktionstemplate.
- Andernfalls, wenn die Suche ein Klassentemplate, Variablentemplate oder Aliastemplate findet, repräsentiert das Ergebnis dieses Template.
- Andernfalls, wenn die Suche einen Typ-Templateparameter findet, repräsentiert das Ergebnis den Typ des entsprechenden Arguments.
- Andernfalls, wenn die Suche einen Typedef-Namen oder Typalias findet, repräsentiert das Ergebnis diesen Typalias.
template<typename T>
struct S {
static constexpr std::meta::info r = ^^T;
using type = T;
};
static_assert(S<int>::r == ^^int); // OK
static_assert(^^S<int>::type != ^^int); // OK
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
- Andernfalls, wenn die Suche einen Klassentyp oder einen Aufzählungstyp findet, repräsentiert das Ergebnis diesen Typ.
- Andernfalls, wenn die Suche ein Klassenmember einer anonymen Union findet, repräsentiert das Ergebnis dieses Member.
- Andernfalls wird der Reflexionsname als ID-Ausdruck betrachtet (siehe Form (4) unten).
^^type-id repräsentiert eine Entität, die wie folgt bestimmt wird:
- Wenn die Typ-ID einen Platzhaltertyp bezeichnet (z.B.
auto), ist der Ausdruck ungültig. - Andernfalls, wenn die Typ-ID ein Aliastemplate mit einer Templateargumentliste benennt, repräsentiert das Ergebnis den so benannten Typalias. (Andere Formen von Typaliasnamen würden als Reflexionsname behandelt, und das Ergebnis würde ebenfalls den Typalias repräsentieren.)
- Andernfalls repräsentiert das Ergebnis den durch die Typ-ID bezeichneten Typ.
^^id-expression repräsentiert eine Entität, die wie folgt bestimmt wird:
- Wenn der ID-Ausdruck bezeichnet:
- eine Variable, die durch eine Lambda-Init-Capture deklariert wurde,
- eine funktionslokale vordefinierte Variable (
__func__), - einen lokalen Parameter, der durch einen
requires-Ausdruck deklariert wurde, oder - eine lokale Entität, bei der ein Lambda-Gültigkeitsbereich zwischen dem Punkt, an dem sie eingeführt wird, und dem Reflexionsausdruck liegt (unabhängig davon, ob die Entität gefangen ist oder nicht),
- ist der Ausdruck ungültig.
- Andernfalls, wenn der ID-Ausdruck eine Überladungsmenge bezeichnet, muss die Überladungsauflösung eine eindeutige Funktion auswählen. Das Ergebnis repräsentiert diese Funktion.
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
- Andernfalls, wenn der ID-Ausdruck eine Variable, strukturierte Bindung, einen Enumerator oder ein nicht-statisches Datenmember bezeichnet, repräsentiert das Ergebnis diese Entität.
- Andernfalls (z.B. wenn der ID-Ausdruck einen Nicht-Typ-Templateparameter oder einen Paketindexierungsausdruck bezeichnet), ist der Ausdruck ungültig.
Der Operand ist ein nicht ausgewerteter Operand.
Anmerkungen
Ein Reflexionswert kann auch durch std::meta::reflect_constant, std::meta::reflect_object, std::meta::reflect_function oder durch Standardinitialisierung von std::meta::info erzeugt werden. Darüber hinaus kann ein Reflexionswert durch Aufruf von <Meta>-Funktionen mit vorhandenen std::meta::info-Objekten erhalten werden.
Wenn ein Typalias als Teil einer Typ-ID erscheint, bewahrt der Reflexionsoperator den Typalias nicht.
using T = int;
static_assert(^^T != ^^int);
static_assert(^^T& == ^^int&);
static_assert(^^T const == ^^const int);
Beispiel
int arr[] = {1, 2, 3};
auto [a1, a2, a3] = arr;
[[=1]] void fn(int n);
enum Enum { A };
using Alias = int;
struct S { int mem; };
template<auto> struct TCls {};
template<auto> void TFn();
template<auto> int TVar;
template<auto N> using TAlias = TCls<N>;
template<auto> concept Concept = true;
namespace NS {}
namespace NSAlias = NS;
constexpr auto r_arr = ^^arr; // represents a variable
constexpr auto r_sb = ^^a3; // represents a structured binding
constexpr auto r_fn = ^^fn; // represents a function
constexpr auto r_enum = ^^Enum::A; // represents an enumerator
constexpr auto r_alias = ^^Alias; // represents a type alias
constexpr auto r_type = ^^S; // represents a type
constexpr auto r_mem = ^^S::mem; // represents a class member
constexpr auto r_tcls = ^^TCls; // represents a class template
constexpr auto r_tfn = ^^TFn; // represents a function template
constexpr auto r_tvar = ^^TVar; // represents a variable template
constexpr auto r_ttype = ^^TAlias; // represents an alias template
constexpr auto r_cncpt = ^^Concept; // represents a concept
constexpr auto r_ns = ^^NS; // represents a namespace
constexpr auto r_ns2 = ^^NSAlias; // represents a namespace alias
int main() {}
Siehe auch
(C++26) |
gibt eine Reflexion zurück, die einen Wert oder ein Templateparameterobjekt repräsentiert, geeignet zur Verwendung als konstantes Templateargument (Funktionstemplate) |
(C++26) |
gibt eine Reflexion zurück, die ein Objekt repräsentiert, geeignet zur Verwendung als konstantes Templateargument (Funktionstemplate) |
(C++26) |
gibt eine Reflexion zurück, die eine Funktion repräsentiert, geeignet zur Verwendung als konstantes Templateargument (Funktionstemplate) |