反射扩展
C++ 反射扩展, ISO/IEC TS 23619:2021 ,指定对核心语言的更改并对 C++ 标准库定义此页面上列出的新组件。
反射 TS 基于 C++20 标准(除了概念的定义以概念 TS 的风格指定)。
核心语言更改
reflexpr 说明符
reflexpr-说明符 形式为 reflexpr
(
reflexpr-操作数 )
,并指定一个元对象类型(见后述)。
reflexpr-操作数 能为下列之一:
::
|
(1) | ||||||||
类型标识 | (2) | ||||||||
嵌套名说明符(可选) 命名空间名 | (3) | ||||||||
标识表达式 | (4) | ||||||||
( 表达式 )
|
(5) | ||||||||
函数调用表达式 | (6) | ||||||||
函数式类型转换表达式 | (7) | ||||||||
其中 函数调用表达式 为
后缀表达式 ( 表达式列表(可选) )
|
|||||||||
而 函数式类型转换表达式 为以下种类的进行显式转型的表达式:
简单类型说明符 ( 表达式列表(可选) )
|
(1) | ||||||||
typename-说明符 ( 表达式列表(可选) )
|
(2) | ||||||||
简单类型说明符 花括号初始化器列表 | (3) | ||||||||
typename-说明符 花括号初始化器列表 | (4) | ||||||||
给 reflexpr-说明符 的操作数应当是类型、命名空间、枚举项、变量、数据成员、函数形参、被捕获实体、 函数调用表达式 或 函数式类型转换表达式 及有括号表达式。 reflexpr(::) 反射全局命名空间。
对于形式为 (
表达式 )
的 reflexpr-操作数 , 表达式 应当为(可能有多重括号的) 函数调用表达式 或 函数式类型转换表达式 。
若无括号的操作数能被当作 类型标识 或 函数式类型转换表达式 ,则它被当作 类型标识 。能用括号消歧义函数风格转型与 类型标识 。例如,给定的拥有默认构造函数的类类型 X
, reflexpr(X()) 反射函数类型 X() ,而 reflexpr((X())) 反射表达式 X() 。
若操作数一并指代别名和类名,则 reflexpr 说明符所表示的类型反射别名并满足 reflect::Alias
。
若操作数指代声明被围绕在块作用域内的名字且该具名实体既非捕获亦非函数形参,则程序非良构。
元对象类型
元对象类型是无名、不完整的命名空间作用域类类型。一个类型满足概念 reflect::Object
当且仅当它是元对象类型。元对象类型亦可能满足其他概念,取决于 reflexpr
的操作数。
重复应用 reflexpr
到同一操作数是产生同一类型还是不同类型是未指定的。若元对象类型反射不完整类类型,则不能应用某些类型变换。
元对象类型允许通过类型表征或其上的类型变换查询 reflexpr
的操作数的某些属性。
重载决议
若 函数调用表达式 的 后缀表达式 拥有类类型,例如 是 函数调用表达式 e(args) 中的 e 拥有类类型,则 后缀表达式 ( e )的类型的用户定义转换函数不应当被使用。
若 后缀表达式 不拥有类类型,则它应当指名作为重载决议唯一结果的函数。
struct Functor { void operator()(int) const; using fptr_t = void(*)(std::nullptr_t); operator fptr_t() const; }; using Meta0 = reflexpr(Functor{}(0)); // OK // using Meta1 = reflexpr(Functor{}(nullptr)); // 错误:使用了转换函数
反射相关
别名是 typedef 声明、别名声明或 using 声明所引入的名字。
实体或别名 B
反射相关到实体或别名 A
,若
-
A
与B
为同一实体或别名, -
A
为变量或枚举项而B
为A
的类型, -
A
为枚举而B
为A
的底层类型, -
A
为类而B
为A
的成员或基类, -
A
为指代实体B
的非模板别名, -
A
不是全局命名空间而B
是A
的外围类或外围命名空间, -
A
为有括号表达式 (B
) , -
A
为闭包类型B
的 lambda 捕获, -
A
为 lambda 捕获B
的闭包类型, -
B
为 函数式类型转换表达式A
所指定的类型, -
B
为重载决议对 函数调用表达式A
所选择的函数, -
B
为函数A
的返回类型、形参类型或函数类型,或 -
B
反射相关到实体或别名X
而X
反射相关到A
。
反射相关关系为自反和传递,但非对称。
不正式而言, B
反射相关到 A
的情况表示 B
参与 A
的声明或定义。
零或多次相继应用产生元对象类型的类型变换到 reflexpr-说明符 所代表的类型,使得用户能查阅反射相关到操作数的实体和别名;我们称这种元对象类型反射相应的反射相关的类型或实体。
struct X; struct B { using X = ::X; typedef X Y; }; struct D : B { using B::Y; }; // ::X ,但非 B::X 或 B::Y 反射相关到 D::Y
杂项
- 用作 reflexpr-操作数 的表达式为不求值表达式并被潜在常量求值。
- 对于确定以捕获默认在 lambda 表达式中捕获的变量的目的,不认为
reflexpr
操作数是不求值操作数。 - 元对象类型
T
所反射的函数或拥有静态存储期的变量被 std::experimental::reflect::get_pointer<T> 的特化 odr 式使用,如同通过取指名该函数或变量的标识表达式的地址。 - 元对象类型能有多于一个定义,只要此类型上的所有操作都产生相同的常量表达式结果。
- 一个类型为待决,若它为 reflexpr 说明符所指代,且操作数
关键词
预定义功能特性测试宏
__cpp_reflection |
至少为 201902 的值,指示反射 TS 受到支持 (宏常量) |
库支持
概念
定义于头文件
<experimental/reflect> | |
定义于命名空间
std::experimental::reflect | |
定义于内联命名空间
std::experimental::reflect::v1 | |
(反射 TS) |
指定类型为元对象类型 (概念) |
(反射 TS) |
指定元对象类型为元对象序列类型 (概念) |
(反射 TS) |
指定元对象类型反射模板形参作用域 (概念) |
(反射 TS) |
指定元对象类型反射具有关联(可能为空的)名字的实体 (概念) |
(反射 TS) |
指定元对象类型反射类型别名、命名空间别名或由 using 声明引入的别名 (概念) |
(反射 TS) |
指定元对象类型反射类的 成员说明 (概念) |
(反射 TS) |
指定元对象类型反射枚举项 (概念) |
(反射 TS) |
指定元对象类型反射变量或数据成员 (概念) |
(反射 TS) |
指定元对象类型满足 RecordMember 、 Enumerator 或 Variable ,或反射全局命名空间以外的命名空间 (概念) |
(反射 TS) |
指定元对象类型反射具有类型的实体 (概念) |
(反射 TS) |
指定元对象类型反射命名空间 (概念) |
(反射 TS) |
指定元对象类型反射全局命名空间 (概念) |
(反射 TS) |
指定元对象类型反射非联合类类型 (概念) |
(反射 TS) |
指定元对象类型反射枚举类型 (概念) |
(反射 TS) |
指定元对象类型反射类类型 (概念) |
(反射 TS) |
指定元对象类型反射命名空间、类、枚举、闭包类型、模板实参作用域 (概念) |
(反射 TS) |
指定元对象类型反射一个类型 (概念) |
(反射 TS) |
指定元对象类型反射枚举项或 constexpr 变量 (概念) |
(反射 TS) |
指定元对象类型反射从 get_base_classes 获得的直接基类 (概念) |
(反射 TS) |
指定元对象类型反射模板形参 (概念) |
(反射 TS) |
指定元对象类型反射函数(包括构造函数与析构函数) (概念) |
(反射 TS) |
指定元对象类型反射表达式 (概念) |
(反射 TS) |
指定元对象类型反射有括号表达式 (概念) |
(反射 TS) |
指定元对象类型反射 函数调用表达式 (概念) |
(反射 TS) |
指定元对象类型反射 函数式类型转换表达式 (概念) |
(反射 TS) |
指定元对象类型反射函数(不含构造函数与析构函数) (概念) |
(反射 TS) |
指定元对象类型反射成员函数I(不含构造函数与析构函数) (概念) |
(反射 TS) |
指定元对象类型反射特殊成员函数 (概念) |
(反射 TS) |
指定元对象类型反射构造函数 (概念) |
(反射 TS) |
指定元对象类型反射析构函数 (概念) |
(反射 TS) |
指定元对象类型反射运算符函数或转换函数 (概念) |
(反射 TS) |
指定元对象类型反射转换函数 (概念) |
(反射 TS) |
指定元对象类型反射非泛型 lambda 的闭包类型 (概念) |
(反射 TS) |
指定元对象类型反射 lambda 捕获 (概念) |
元对象操作
定义于头文件
<experimental/reflect> | |
定义于命名空间
std::experimental::reflect | |
定义于内联命名空间
std::experimental::reflect::v1 | |
| |
(反射 TS) |
检查二个元对象类型是否反射同一实体或别名 (类模板) |
(反射 TS) |
获得被反射实体或别名的声明的预设行号 (类模板) |
(反射 TS) |
获得被反射实体或别名的声明的实现定义列号 (类模板) |
(反射 TS) |
获得被反射实体或别名的声明的预设文件名 (类模板) |
| |
(反射 TS) |
获得元对象序列的大小 (类模板) |
(反射 TS) |
获得元对象序列中拥有给定下标的元对象类型 (类模板) |
(反射 TS) |
应用模板到元对象序列 (类模板) |
| |
(反射 TS) |
检查被反射实体或别名是否具名 (类模板) |
(反射 TS) |
获得被反射实体或别名的无限定名 (类模板) |
(反射 TS) |
获得被反射实体或别名的实现定义显示名 (类模板) |
| |
(反射 TS) |
获得反射被反射别名的关联实体的元对象类型 (类模板) |
| |
(反射 TS) |
获得反射被反射实体或别名的类型的元对象类型 (类模板) |
(反射 TS) |
获得反射被反射实体或别名的类型 (类模板) |
(反射 TS) |
检查元对象类型是否反射枚举类型 (类模板) |
(反射 TS) |
检查元对象类型是否反射联合体类型 (类模板) |
分别检查元对象类型是否反射声明使用 class 或 struct 的非联合类类型 (类模板) | |
| |
(反射 TS) |
获得反射被反射实体或别名的作用域的元对象类型 (类模板) |
| |
(反射 TS) |
获得反射给定基类关系中基类的元对象类型 (类模板) |
| |
(反射 TS) |
检查被反射的成员或基类是否为公开 (类模板) |
(反射 TS) |
检查被反射的成员或基类是否为受保护 (类模板) |
(反射 TS) |
检查被反射的成员或基类是否为私有 (类模板) |
| |
获得元素反射被反射类的公开、可访问或全部数据成员的元对象序列类型 (类模板) | |
获得元素反射被反射类的公开、可访问或全部成员函数的元对象序列类型 (类模板) | |
(反射 TS) |
获得元素反射被反射类的全部构造函数的的元对象序列类型 (类模板) |
(反射 TS) |
获得元素反射声明于被反射类中的所有运算符函数及转换函数的的元对象序列类型 (类模板) |
(反射 TS) |
获得反射被反射类的析构函数的元对象类型 (类模板) |
获得元素反射被反射类的公开、可访问或全部成员类型的元对象序列类型 (类模板) | |
获得元素反射被反射类的公开、可访问或全部基类的元对象序列类型 (类模板) | |
| |
(反射 TS) |
检查被反射枚举是否有作用域 (类模板) |
(反射 TS) |
获得元素反射被反射枚举的枚举项的元对象序列类型 (类模板) |
(反射 TS) |
获得反射被反射枚举的底层类型的元对象类型 (类模板) |
| |
(反射 TS) |
获得作为常量表达式的被反射变量的值 (类模板) |
(反射 TS) |
检查变量是否声明带 thread_local (类模板) |
| |
(反射 TS) |
检查被反射的形参是否有默认实参 (类模板) |
| |
(反射 TS) |
获得元素反射被反射函数的形参的元对象序列类型 (类模板) |
(反射 TS) |
检查被反射函数的形参列表是否含有省略号形参 (类模板) |
(反射 TS) |
检查被反射函数是否为不抛出 (类模板) |
(反射 TS) |
检查被反射函数是否为被删除 (类模板) |
| |
(反射 TS) |
检查被反射变量或函数是否为 constexpr (类模板) |
| |
(反射 TS) |
检查被反射的命名空间或函数是否为 inline (类模板) |
| |
(反射 TS) |
获得反射被反射的有括号表达式的无括号表达式的元对象类型 (类模板) |
| |
(反射 TS) |
获得反射被反射的 函数调用表达式 中的函数的元对象类型 (类模板) |
| |
(反射 TS) |
获得反射被反射的 函数式类型转换表达式 中的构造函数的元对象类型 (类模板) |
| |
(反射 TS) |
获得被反射变量或函数的地址,或指向非静态成员的成员指针值 (类模板) |
| |
分别检查被反射成员函数是否声明带 const、 volatile、 & 或 && 限定符 (类模板) | |
(反射 TS) |
检查被反射的成员函数是否重写基类的成员函数 (类模板) |
| |
(反射 TS) |
检查被反射的类或成员函数是否标记为 final (类模板) |
| |
(反射 TS) |
检查被反射的变量是否拥有静态存储期,或被反射的成员函数是否为静态 (类模板) |
| |
(反射 TS) |
检查被反射的特殊成员函数是否为隐式声明 (类模板) |
(反射 TS) |
检查被反射的成员函数是否在其首条声明预置 (类模板) |
| |
(反射 TS) |
检查被反射的构造函数或转换函数是否声明带 explicit (类模板) |
| |
(反射 TS) |
检查被反射的成员函数是否为虚 (类模板) |
(反射 TS) |
检查被反射的成员函数是否为纯虚 (类模板) |
| |
(反射 TS) |
获得元素反射被反射闭包类型的捕获的元对象序列类型 (类模板) |
分别检查被反射闭包类型的 lambda 表达式的捕获默认是否为 = 或 & (类模板) | |
(反射 TS) |
检查被反射闭包类型的 operator() 是否声明带 const (类模板) |
| |
(反射 TS) |
检查被反射的 lambda 捕获是否被显式捕获 (类模板) |
(反射 TS) |
检查被反射的 lambda 捕获是否为初始化捕获 (类模板) |
库功能特性测试宏
定义于头文件
<experimental/reflect> | |
__cpp_lib_reflection |
至少为 201902 的值,指示反射 TS 的支持库受到支持 (宏常量) |
概念的满足
下表列出反射一个操作数的类型是否满足一个反射 TS 所引入的概念。
类别 | reflexpr 操作数
|
满足的概念 |
---|---|---|
类型 | 指代联合体的 类名 | reflect::Union
|
指代闭包类型的 类名 | reflect::Lambda
| |
指代非 union 类的 类名 | reflect::Record
| |
枚举名 | reflect::Enum
| |
模板 类型形参 | reflect::Type , reflect::Alias
| |
decltype-说明符 | reflect::Type , reflect::Alias
| |
using 声明所引入的 类型名 | reflect::Type , reflect::Alias , reflect::ScopedMember
| |
任何其他 typedef-名 | reflect::Type , reflect::Alias
| |
任何其他 类型标识 | reflect::Type
| |
命名空间 | 命名空间别名 | reflect::Namespace , reflect::Alias
|
全局命名空间 | reflect::GlobalScope
| |
任何其他命名空间 | reflect::Namespace
| |
表达式 | 数据成员名 | reflect::Variable
|
变量名 | reflect::Variable
| |
枚举项名 | reflect::Enumerator
| |
函数形参名 | reflect::FunctionParameter
| |
被捕获实体之名 | reflect::LambdaCapture
| |
带括号表达式 | reflect::ParenthesizedExpression
| |
函数调用表达式 | reflect::FunctionCallExpression
| |
函数式类型转换表达式 | reflect::FunctionalTypeConversion
|
若形式为标识表达式的操作数为常量表达式,则该 reflexpr 说明符所指定的类型亦满足 reflect::Constant
。
若 reflexpr 操作数指代类成员,则该 reflexpr 说明符所表示的类型亦满足 reflect::RecordMember
。
参阅
含有某个类型的信息,由实现生成。 这是 typeid 运算符所返回的类。 (类) | |
(C++11) |
编译时类型信息 |