opérateur de réflexion (depuis C++26)
L'opérateur unaire ^^ opérateur, appelé l'opérateur de réflexion, produit la réflexion du construct linguistique donné, de type std::meta::info.
Syntaxe
^^ ::
|
(1) | ||||||||
^^ reflection-name
|
(2) | ||||||||
^^ type-id
|
(3) | ||||||||
^^ id-expression
|
(4) | ||||||||
| reflection-name | - | un identifiant, éventuellement qualifié, éventuellement en utilisant le désambiguïsateur de modèle. Cette forme a priorité sur type-id et id-expression |
| type-id | - | un type-id |
| id-expression | - | un id-expression |
La plus longue séquence de jetons pouvant syntaxiquement former l'opérande de ^^ est analysée. Si le résultat représente un modèle, l'expression ne doit pas être directement suivie de <.
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
}
Explication
^^:: représente l'espace de noms global.^^reflection-name, le reflection-name est recherché, et la représentation est déterminée comme suit :
- Si la recherche trouve une déclaration qui a remplacé un déclarateur using, l'expression est invalide.
- Sinon, si la recherche trouve un alias d'espace de noms, un espace de noms, ou un concept, le résultat représente cette entité.
- Sinon, si la recherche trouve un modèle :
- Si la recherche trouve un nom-de-classe injecté :
- Si le désambiguïsateur de modèle est présent, le résultat représente le modèle de classe nommé par le nom-de-classe injecté.
- Sinon, le nom-de-classe injecté doit être non ambigu lorsqu'il est considéré comme un nom de type (sinon l'expression est invalide). Le résultat représente le type ainsi nommé.
- Sinon, si la recherche trouve un ensemble de surcharges, cet ensemble de surcharges ne doit contenir que des déclarations d'un modèle de fonction unique. Le résultat représente ce modèle de fonction.
- Sinon, si la recherche trouve un modèle de classe, un modèle de variable, ou un modèle d'alias, le résultat représente ce modèle.
- Sinon, si la recherche trouve un paramètre de modèle de type, le résultat représente le type de l'argument correspondant.
- Sinon, si la recherche trouve un nom de typedef ou un alias de type, le résultat représente cet alias de type.
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
- Sinon, si la recherche trouve un type de classe ou un type d'énumération, le résultat représente ce type.
- Sinon, si la recherche trouve un membre de classe d'une union anonyme, le résultat représente ce membre.
- Sinon, le reflection-name est considéré comme un id-expression (voir la forme (4) ci-dessous).
^^type-id représente une entité déterminée comme suit :
- Si le type-id désigne un type placeholder (par exemple
auto), l'expression est invalide. - Sinon, si le type-id nomme un modèle d'alias avec une liste d'arguments de modèle, le résultat représente l'alias de type ainsi nommé. (Les autres formes de noms d'alias de type seraient traitées comme un reflection-name et le résultat représenterait également l'alias de type.)
- Sinon, le résultat représente le type désigné par le type-id.
^^id-expression représente une entité déterminée comme suit :
- Si le id-expression désigne :
- une variable déclarée par une capture d'initialisation de lambda,
- une variable prédéfinie locale à une fonction (
__func__), - un paramètre local déclaré par une
requiresexpression, ou - une entité locale pour laquelle une portée lambda s'interpose entre le point où elle est introduite et l'expression de réflexion (que l'entité soit capturée ou non),
- l'expression est invalide.
- Sinon, si le id-expression désigne un ensemble de surcharges, la résolution de surcharge doit sélectionner une fonction unique. Le résultat représente cette fonction.
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
- Sinon, si le id-expression désigne une variable, une liaison structurée, un énumérateur, ou un membre de données non statique, le résultat représente cette entité.
- Sinon (par exemple, le id-expression désigne un paramètre de modèle sans type ou une expression d'indexation de paquet), l'expression est invalide.
L'opérande est un opérande non évalué.
Notes
Une valeur de réflexion peut également être produite par std::meta::reflect_constant, std::meta::reflect_object, std::meta::reflect_function, ou en initialisant par défaut std::meta::info. De plus, une valeur de réflexion peut être obtenue en appelant des <fonctions méta> avec des objets std::meta::info existants.
Si un alias de type apparaît dans le cadre d'un type-id, l'opérateur de réflexion ne préserve pas l'alias de type.
using T = int;
static_assert(^^T != ^^int);
static_assert(^^T& == ^^int&);
static_assert(^^T const == ^^const int);
Exemple
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() {}
Voir aussi
(C++26) |
renvoie une réflexion représentant une valeur ou un objet paramètre de modèle, adapté à une utilisation comme argument de modèle constant (modèle de fonction) |
(C++26) |
renvoie une réflexion représentant un objet, adapté à une utilisation comme argument de modèle constant (modèle de fonction) |
(C++26) |
renvoie une réflexion représentant une fonction, adapté à une utilisation comme argument de modèle constant (modèle de fonction) |