Спецификаторы splice (начиная с C++26)
Создаёт языковую конструкцию из значения рефлексии, фактически «встраивая» рефлексию в исходный код.
Синтаксис
[: constant-expression :] | (1) | |
typename [: constant-expression :] | (2) | |
template [: constant-expression :] | (3) |
| constant-expression | - | преобразуемое константное выражение типа std::meta::info |
<>), а сам он должен быть левым операндом оператора разрешения области видимости ::, например template[:R:]<int>::is_always_lock_free.Пояснение
В общем случае спецификатор splice имеет то же значение, что и имя или значение языковой конструкции, представленной constant-expression. Говорят, что он обозначает эту языковую конструкцию.
Выражение
Чтобы спецификатор splice являлся выражением, он не должен следовать за ключевым словом typename и за ним не должен следовать оператор разрешения области видимости ::.
struct S { static constexpr int a = 1; };
template<typename> struct TCls { static constexpr int b = 2; };
constexpr int c = [:^^S:]::a; // [:^^S:] is not an expression
constexpr int d = template [:^^TCls:]<int>::b; // template [:^^TCls:]<int> is not an expression
template<auto V> constexpr int e = [:V:]; // [:V:] is an expression
constexpr int f = template [:^^e:]<^^S::a>; // template [:^^e:]<^^S::a> is an expression
constexpr auto g = typename [:^^int:](42); // typename [:^^int:] is a type specifier
Невзятие в скобки выражение splice не может быть аргументом шаблона.
Выражение splice может обозначать функцию, объект, член данных, переменную, структурированное связывание, значение или перечислитель. Однако оно не может обозначать конструктор, деструктор, безымянное битовое поле или локальную сущность, если её именование приведёт к захвату лямбда-выражением.
Выражение splice, обозначающее переменную или структурированное связывание V, допустимо только в том случае, если V имеет статическую или потоковую длительность хранения либо объявлен в области видимости, охватывающей выражение.
Выражение splice, обозначающее нестатический член данных или неявную нестатическую функцию-член, можно использовать только:
- в качестве второго операнда выражения доступа к члену класса;
- в качестве операнда оператора взятия адреса для формирования указателя на член;
- в невычисляемом операнде, если оно обозначает нестатический член данных.
В отличие от имён нестатических членов, выражение splice [:r:] никогда не преобразуется неявно в this->[:r:].
Выражение splice [:r:] может описывать отношение прямого базового класса (D, B) (например, если r является элементом std::meta::bases_of(^^D, ctx)). Отношение прямого базового класса может встречаться только в качестве второго операнда выражения доступа к члену класса. Это выражение доступа к члену класса преобразует первый операнд в «ссылку на (возможно, квалифицированный D)» и задаёт подобъект прямого базового класса B преобразованного значения. Это можно использовать для доступа к базовому классу, который в противном случае был бы неоднозначным или недоступным.
Выражение splice может обозначать шаблон функции или шаблон переменной только при использовании ключевого слова template.
Тип
За спецификатором splice, являющимся спецификатором типа, не должен следовать оператор разрешения области видимости ::; перед ним должен находиться typename либо он должен использоваться в контексте, допускающем только тип.
template<std::meta::info R> void tfn() {
typename [:R:]::type m; // OK, typename applies to the qualified name
// (Here [:R:] is a scope, not a type specifier.)
}
struct S { using type = int; };
void fn() {
[:^^S::type:] *var; // error: [:^^S::type:] is an expression
typename [:^^S::type:] *var; // OK, declares variable with type int*
}
using alias = [:^^S::type:]; // OK, type-only context
Спецификатор типа splice может обозначать тип, шаблон класса или шаблон псевдонима. Если он обозначает шаблон и не содержит списка аргументов шаблона, к нему применяется выведение аргументов шаблона класса.
Спецификатор splice также может использоваться в требовании к типу.
template<typename T> concept C = requires {
typename [:T::r1:]; // fails if T::r1 is not a reflection of a type
typename [:T::r2:]<int>; // fails if T::r2 is not a reflection of some template Z
// for which Z<int> is a type
};
Область видимости
Если спецификатор splice является левым операндом оператора разрешения области видимости ::, то при наличии у спецификатора списка аргументов шаблона перед ним должен находиться typename или template.
template<int V>
struct TCls {
static constexpr int s = V;
using type = int;
};
int v1 = [:^^TCls<1>:]::s;
int v2 = template [:^^TCls:]<2>::s; // OK, 'template' is part of the splice specifier
typename [:^^TCls:]<3>::type v3 = 3; // OK, 'typename' is part of the typename-specifier
template [:^^TCls:]<3>::type v4 = 4; // OK, 'template' is part of the splice specifier
typename template [:^^TCls:]<3>::type v5 = 5; // OK, same as v3
[:^^TCls:]<3>::type v6 = 6; // error: unexpected <
Спецификатор splice должен обозначать тип класса или перечисления либо пространство имён. Спецификатор splice в [:r:]<TArgs...>:: или template[:r:]<TArgs...>:: должен обозначать шаблон класса или шаблон псевдонима.
Пространство имён
Спецификатор splice [:r:] в определении псевдонима пространства имён или в директиве using должен обозначать имя пространства имён или псевдоним пространства имён, не являющийся глобальным пространством имён. Зависимый r может встречаться в определении псевдонима пространства имён (но не в директиве using), в результате чего псевдоним пространства имён также становится зависимым.
Примечания
Помимо спецификаторов splice, шаблоны функций std::meta::extract и std::meta::substitute также могут преобразовывать рефлексию в представляемое ею значение. В отличие от спецификаторов splice, для них не требуется, чтобы аргументы по отдельности являлись константными выражениями, однако на них распространяются другие ограничения.
Пример
См. также
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/splice_specifiers