Spec-Zone.ru › C++

оператор отражения (начиная с C++26)

Унарный оператор ^^, называемый оператором отражения, возвращает рефлексию заданной языковой конструкции типа std::meta::info.

Синтаксис

^^ :: (1)
^^ имя-рефлексии (2)
^^ идентификатор-типа (3)
^^ выражение-идентификатор (4)
имя-рефлексии - идентификатор, при необходимости с указанием квалификаторов, при необходимости с использованием уточняющего ключевого слова template. Эта форма имеет приоритет над идентификатором-типа и выражением-идентификатором
идентификатор-типа - идентификатор-типа
выражение-идентификатор - выражение-идентификатор

Разбирается самая длинная последовательность токенов, которая синтаксически может образовать операнд ^^. Если результат обозначает шаблон, непосредственно за выражением не должно следовать <.

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
}

Пояснение

1) Выражение ^^:: обозначает глобальное пространство имён.
2) В ^^reflection-name выполняется поиск имени-рефлексии, а представление определяется следующим образом:
  • Если при поиске найдено объявление, заменившее декларатор using, выражение некорректно.
  • Иначе, если при поиске найден псевдоним пространства имён, пространство имён или концепт, результат обозначает эту сущность.
  • Иначе, если при поиске найден шаблон:
  • Если при поиске найдено внедрённое имя класса:
    • Если присутствует уточняющее ключевое слово template, результат обозначает шаблон класса, именуемый внедрённым именем класса.
    • Иначе внедрённое имя класса должно быть однозначным при рассмотрении в качестве имени типа (в противном случае выражение некорректно). Результат обозначает названный таким образом тип.
  • Иначе, если при поиске найден набор перегрузок, он должен содержать объявления только одного уникального шаблона функции. Результат обозначает этот шаблон функции.
  • Иначе, если при поиске найден шаблон класса, шаблон переменной или шаблон псевдонима, результат обозначает этот шаблон.
  • Иначе, если при поиске найден параметр шаблона, являющийся типом параметра шаблона, результат обозначает тип соответствующего аргумента.
  • Иначе, если при поиске найдено имя typedef или псевдоним типа, результат обозначает этот псевдоним типа.
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
  • Иначе, если при поиске найден тип класса или тип перечисления, результат обозначает этот тип.
  • Иначе, если при поиске найден член класса из анонимного объединения, результат обозначает этот член.
  • Иначе имя-рефлексии рассматривается как выражение-идентификатор (см. форму (4) ниже).
3) Выражение ^^type-id обозначает сущность, определяемую следующим образом:
  • Если идентификатор-типа обозначает тип-заполнитель (например, auto), выражение некорректно.
  • Иначе, если идентификатор-типа задаёт шаблон псевдонима со списком аргументов шаблона, результат обозначает названный таким образом псевдоним типа. (Другие формы записи имени псевдонима типа рассматривались бы как имя-рефлексии, и результат также обозначал бы псевдоним типа.)
  • Иначе результат обозначает тип, заданный идентификатором-типа.
4) Выражение ^^id-expression обозначает сущность, определяемую следующим образом:
  • Если выражение-идентификатор обозначает:
  • переменную, объявленную посредством инициализирующего захвата лямбда-выражения,
  • предопределённую переменную локальной функции (__func__),
  • локальный параметр, объявленный в выражении requires, или
  • локальную сущность, для которой между точкой её введения и выражением отражения находится область видимости лямбда-выражения (независимо от того, захвачена эта сущность или нет),
выражение некорректно.
  • Иначе, если выражение-идентификатор обозначает набор перегрузок, разрешение перегрузки должно выбрать единственную функцию. Результат обозначает эту функцию.
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
  • Иначе, если выражение-идентификатор обозначает переменную, структурированную привязку, элемент перечисления или нестатический член данных, результат обозначает эту сущность.
  • Иначе (например, если выражение-идентификатор обозначает нетиповой параметр шаблона или выражение индексации пакета), выражение некорректно.

Операнд является невычисляемым операндом.

Примечания

Значение рефлексии также можно получить с помощью std::meta::reflect_constant, std::meta::reflect_object, std::meta::reflect_function или посредством инициализации по умолчанию std::meta::info. Кроме того, значение рефлексии можно получить, вызвав функции <meta> с существующими объектами std::meta::info.

Если псевдоним типа входит в состав идентификатора-типа, оператор отражения не сохраняет этот псевдоним типа.

using T = int;
static_assert(^^T != ^^int);
static_assert(^^T& == ^^int&);
static_assert(^^T const == ^^const int);

Пример

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() {}

См. также

  • спецификаторы splice
reflect_constant
(C++26)
возвращает рефлексию, представляющую значение или объект параметра шаблона, пригодную для использования в качестве аргумента шаблона времени компиляции
(шаблон функции)
reflect_object
(C++26)
возвращает рефлексию, представляющую объект, пригодную для использования в качестве аргумента шаблона времени компиляции
(шаблон функции)
reflect_function
(C++26)
возвращает рефлексию, представляющую функцию, пригодную для использования в качестве аргумента шаблона времени компиляции
(шаблон функции)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/operator_reflection

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API