operador de reflexión (desde C++26)
El operador unario ^^, llamado operador de reflexión, produce la reflexión de la construcción de lenguaje dada, de tipo std::meta::info.
Sintaxis
^^ ::
|
(1) | ||||||||
^^ nombre-de-reflexión
|
(2) | ||||||||
^^ tipo-id
|
(3) | ||||||||
^^ expresión-id
|
(4) | ||||||||
| nombre-de-reflexión | - | un identificador, opcionalmente calificado, opcionalmente usando desambiguador de plantilla. Esta forma tiene precedencia sobre tipo-id y expresión-id |
| tipo-id | - | un tipo-id |
| expresión-id | - | una expresión-id |
La secuencia más larga de tokens que sintácticamente podría formar el operando de ^^ es analizada. Si el resultado representa una plantilla, la expresión no debe ir seguida directamente por <.
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
}
Explicación
^^:: representa el espacio de nombres global.^^reflection-name, el nombre-de-reflexión es buscado, y la representación se determina de la siguiente manera:
- Si la búsqueda encuentra una declaración que reemplazó un declarador-using, la expresión es inválida.
- De lo contrario, si la búsqueda encuentra un alias de espacio de nombres, un espacio de nombres, o un concepto, el resultado representa esa entidad.
- De lo contrario, si la búsqueda encuentra una plantilla:
- Si la búsqueda encuentra un nombre-de-clase-inyectado:
- Si el desambiguador de plantilla está presente, el resultado representa la plantilla de clase nombrada por el nombre-de-clase-inyectado.
- De lo contrario, el nombre-de-clase-inyectado debe ser no ambiguo cuando se considera como un nombre de tipo (de lo contrario, la expresión es inválida). El resultado representa el tipo así nombrado.
- De lo contrario, si la búsqueda encuentra un conjunto de sobrecarga, ese conjunto de sobrecarga debe contener solo declaraciones de una plantilla de función única. El resultado representa esa plantilla de función.
- De lo contrario, si la búsqueda encuentra una plantilla de clase, una plantilla de variable, o una plantilla de alias, el resultado representa esa plantilla.
- De lo contrario, si la búsqueda encuentra un parámetro de plantilla de tipo, el resultado representa el tipo del argumento correspondiente.
- De lo contrario, si la búsqueda encuentra un nombre typedef o un alias de tipo, el resultado representa ese alias de tipo.
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
- De lo contrario, si la búsqueda encuentra un tipo de clase o un tipo de enumeración, el resultado representa ese tipo.
- De lo contrario, si la búsqueda encuentra un miembro de clase de una unión anónima, el resultado representa ese miembro.
- De lo contrario, el nombre-de-reflexión se considera una expresión-id (véase la forma (4) a continuación).
^^type-id representa una entidad determinada de la siguiente manera:
- Si el tipo-id designa un tipo placeholder (p.ej.
auto), la expresión es inválida. - De lo contrario, si el tipo-id nombra una plantilla de alias con una lista de argumentos de plantilla, el resultado representa el alias de tipo así nombrado. (Otra forma de nombres de alias de tipo sería tratada como un nombre-de-reflexión, y el resultado también representaría el alias de tipo.)
- De lo contrario, el resultado representa el tipo denotado por el tipo-id.
^^id-expression representa una entidad determinada de la siguiente manera:
- Si la expresión-id denota:
- una variable declarada por una captura-init de lambda,
- una variable predefinida local a una función (
__func__), - un parámetro local declarado por una expresión
requires, o - una entidad local para la que un ámbito de lambda interviene entre el punto en que se introduce y la expresión de reflexión (ya sea que la entidad sea capturada o no),
- la expresión es inválida.
- De lo contrario, si la expresión-id denota un conjunto de sobrecarga, la resolución de sobrecarga debe seleccionar una función única. El resultado representa esa función.
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
- De lo contrario, si la expresión-id denota una variable, un enlace estructurado, un enumerador, o un miembro de datos no estático, el resultado representa esa entidad.
- De lo contrario (p.ej. la expresión-id denota un parámetro de plantilla que no es de tipo o una expresión de indexación de paquete), la expresión es inválida.
El operando es un operando no evaluado.
Notas
Un valor de reflexión también puede ser producido por std::meta::reflect_constant, std::meta::reflect_object, std::meta::reflect_function, o mediante inicialización por defecto de std::meta::info. Además, se puede obtener un valor de reflexión llamando a funciones <meta> con objetos std::meta::info existentes.
Si un alias de tipo aparece como parte de un tipo-id, el operador de reflexión no preserva el alias de tipo.
using T = int;
static_assert(^^T != ^^int);
static_assert(^^T& == ^^int&);
static_assert(^^T const == ^^const int);
Ejemplo
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() {}
Véase también
(C++26) |
devuelve una reflexión que representa un valor o un objeto parámetro de plantilla, adecuado para usar como argumento de plantilla constante (plantilla de función) |
(C++26) |
devuelve una reflexión que representa un objeto, adecuado para usar como argumento de plantilla constante (plantilla de función) |
(C++26) |
devuelve una reflexión que representa una función, adecuado para usar como argumento de plantilla constante (plantilla de función) |