反射运算符 (C++26 起) - cppreference.com
来自cppreference.com
一元 ^^ 运算符,也称反射运算符,生成给定语言构造的反射——std::meta::info 类型。
语法
^^ ::
|
(1) | ||||||||
^^ 反射名
|
(2) | ||||||||
^^ 类型标识
|
(3) | ||||||||
^^ 标识表达式
|
(4) | ||||||||
| 反射名 | - | 一个标识符,可选地限定,可选地使用模板指明标记(也称模板消歧义符)。这种形式优先于 类型标识 和 标识表达式 |
| 类型标识 | - | 一个类型标识 |
| 标识表达式 | - | 一个标识表达式 |
会解析语法上能构成 ^^ 操作数的最长记号序列。如果结果表示的是模板,那么表达式一定不能直接紧跟 <。
static_assert(std::meta::is_type(^^int())); // ^^int() 表示类型 int() // 不是对 ^^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; // 错误:^^ 应用于 类型标识 int&& r == ^^int & true; // 错误:^^ 应用于 类型标识 int& r == (^^int) && true; // 正确 r == ^^int &&&& true; // 错误:int &&&& 不是一个有效的 类型标识 ^^X < xv; // 错误:表示模板的反射表达式紧跟 < (^^X) < xv; // 正确 ^^X<true> < xv; // 正确 }
解释
1) 表达式 ^^:: 表示全局命名空间。
2) 在 ^^反射名 中,对 反射名 进行查找,并按如下方式确定其表示:
- 如果查找发现一个注入类名:
- 如果存在
template消歧义符,则结果表示注入类名指名的类模板。 - 否则,当把注入类名作为类型名使用时,它必须不产生歧义(否则该表达式无效)。结果表示被指名的类型。
- 如果存在
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,表示类型别名 Y constexpr std::meta::info f = ^^Z; // OK,表示类型别名 Z,而不是类型 Z
3) 表达式 ^^类型标识 表示一个按如下方式确定的实体:
4) 表达式 ^^标识表达式 表示一个按如下方式确定的实体:
- 如果 标识表达式 代表:
- 那么表达式无效。
- 否则,如果 标识表达式 指代一个重载集,那么重载决议必须选出唯一函数。结果表示该函数。
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>; // 正确 constexpr std::meta::info b = ^^fn<int>; // 错误:有歧义
其操作数是一个不求值操作数。
注解
反射值也可以使用 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; // 表示变量 constexpr auto r_sb = ^^a3; // 表示结构化绑定 constexpr auto r_fn = ^^fn; // 表示函数 constexpr auto r_enum = ^^Enum::A; // 表示枚举项 constexpr auto r_alias = ^^Alias; // 表示类型别名 constexpr auto r_type = ^^S; // 表示类型 constexpr auto r_mem = ^^S::mem; // 表示类成员 constexpr auto r_tcls = ^^TCls; // 表示类模板 constexpr auto r_tfn = ^^TFn; // 表示函数模板 constexpr auto r_tvar = ^^TVar; // 表示变量模板 constexpr auto r_ttype = ^^TAlias; // 表示别名模板 constexpr auto r_cncpt = ^^Concept; // 表示概念 constexpr auto r_ns = ^^NS; // 表示命名空间 constexpr auto r_ns2 = ^^NSAlias; // 表示命名空间别名 int main() {}