Extensions for reflection
C++反射扩展规范(ISO/IEC TS 23619:2021)规定了核心语言的修改,并定义了本页所列的C++标准库新组件。
Reflection TS 基于 C++20 标准(除概念定义采用 Concepts TS 风格进行规范外)。
核心语言变更
reflexpr 说明符
reflexpr-specifier
的形式为
reflexpr
(
reflexpr-operand
)
,用于指定元对象类型(详见下文)。
reflexpr-operand 可以是以下之一:
::
|
(1) | ||||||||
| 类型标识 | (2) | ||||||||
| 嵌套名称说明符 (可选) 命名空间名称 | (3) | ||||||||
| 标识表达式 | (4) | ||||||||
(
表达式
)
|
(5) | ||||||||
| 函数调用表达式 | (6) | ||||||||
| 函数式类型转换表达式 | (7) | ||||||||
其中 function-call-expression 为
后缀表达式
(
表达式列表
(可选)
)
|
|||||||||
以及 functional-type-conv-expression 是执行以下类型 显式转换 的表达式类别:
简单类型说明符
(
表达式列表
(可选)
)
|
(1) | ||||||||
类型名说明符
(
表达式列表
(可选)
)
|
(2) | ||||||||
| 简单类型说明符 花括号初始化列表 | (3) | ||||||||
| 类型名说明符 花括号初始化列表 | (4) | ||||||||
reflexpr-说明符 的操作数应为 类型 、 命名空间 、 枚举项 、变量、 数据成员 、 函数形参 、 被捕获实体 、 function-call-expression 或 functional-type-conv-expression ,以及带括号的表达式。 reflexpr ( :: ) 反映全局命名空间。
对于形式为
(
expression
)
的
reflexpr-操作数
,该
expression
应为(可能多重括号包围的)
function-call-expression
或
functional-type-conv-expression
。
如果一个未加括号的操作数既可以被视为
type-id
也可以被视为
functional-type-conv-expression
,则将其视为
type-id
。括号可用于消除函数式转换与
type-id
之间的歧义。例如,对于具有默认构造函数的类类型
X
,
reflexpr
(
X
(
)
)
反映的是函数类型
X
(
)
,而
reflexpr
(
(
X
(
)
)
)
反映的是表达式
X
(
)
。
如果操作数同时指定了别名和类名,reflexpr说明符表示的类型反映该别名并满足
reflect::Alias
要求。
如果操作数指定的名称其声明位于块作用域内,且该命名实体既未被捕获也不是函数参数,则程序非良构。
元对象类型
meta-object type
是一个未命名的、不完整的命名空间作用域类类型。当且仅当某个类型是元对象类型时,该类型满足概念
reflect::Object
。根据
reflexpr
操作数的不同,元对象类型可能满足其他概念。
反复对同一操作数应用
reflexpr
是否产生相同类型还是不同类型是未指定的。如果元对象类型反映的是不完整类类型,则无法应用某些类型转换。
元对象类型允许通过类型特征或类型转换对
reflexpr
操作数的某些属性进行检查。
重载解析
如果 function-call-expression 的 postfix-expression 具有类类型,即 function-call-expression e ( args ) 中的 e 具有类类型,则不应使用该 postfix-expression 类型( e )的 user-defined conversion function 。
如果 postfix-expression 不是类类型,它应当命名一个作为重载决议唯一结果的函数。
struct Functor { void operator()(int) const; using fptr_t = void(*)(std::nullptr_t); operator fptr_t() const; }; using Meta0 = reflexpr(Functor{}(0)); // 正确 // 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-specifier 所表示的类型进行零次或多次连续的元对象类型转换,可实现对与操作数具有反射关联的实体和别名进行检测;此类元对象类型被称为反射相应反射关联实体或别名。
struct X; struct B { using X = ::X; typedef X Y; }; struct D : B { using B::Y; }; // 只有 ::X 与 D::Y 存在反射关联,B::X 和 B::Y 则无此关联
杂项
- 用作 reflexpr-操作数 的表达式是 未求值表达式 且 可能进行常量求值 。
-
为确定通过捕获默认值
在lambda表达式中捕获的变量
,
reflexpr操作数不被视为未求值操作数。 -
通过元对象类型
T反射的静态 存储期 函数或变量,会被特化 std :: experimental :: reflect :: get_pointer < T > 显式使用 ,如同通过获取命名该函数或变量的标识表达式地址。 - 只要对该类型的所有操作产生相同的常量表达式结果,元对象类型可以存在多个定义。
- 若类型由reflexpr说明符表示且操作数满足以下条件,则该类型为 依赖类型 :
关键词
预定义功能测试宏
|
__cpp_reflection
(reflection TS)
|
至少为
201902
的值表示支持反射技术规范
(宏常量) |
库支持
概念
|
定义于头文件
<experimental/reflect>
|
|
|
定义于 命名空间
std::experimental::reflect
|
|
|
定义于内联命名空间
std::experimental::reflect::v1
|
|
|
(reflection TS)
|
指定某个类型为元对象类型
(concept) |
|
(reflection TS)
|
指定元对象类型为元对象序列类型
(concept) |
|
(reflection TS)
|
指定元对象类型反映模板参数作用域
(concept) |
|
(reflection TS)
|
指定元对象类型反映具有关联(可能为空)名称的实体或别名
(concept) |
|
(reflection TS)
|
指定元对象类型反映的是类型别名、命名空间别名或由 using 声明引入的别名
(concept) |
|
(reflection TS)
|
指定元对象类型反映类的
member-declaration
(concept) |
|
(reflection TS)
|
指定元对象类型反映枚举器
(concept) |
|
(reflection TS)
|
指定元对象类型反映变量或数据成员
(concept) |
|
(reflection TS)
|
指定一个元对象类型满足
RecordMember
、
Enumerator
或
Variable
的要求,或者反映除全局命名空间之外的命名空间
(概念) |
|
(reflection TS)
|
指定元对象类型反映具有类型的实体
(concept) |
|
(reflection TS)
|
指定元对象类型反映的是命名空间
(concept) |
|
(reflection TS)
|
指定元对象类型反映全局命名空间
(concept) |
|
(reflection TS)
|
指定元对象类型反映非联合类类型
(概念) |
|
(reflection TS)
|
指定元对象类型反映枚举类型
(concept) |
|
(reflection TS)
|
指定元对象类型反映类类型
(概念) |
|
(reflection TS)
|
指定元对象类型反映的是命名空间、类、枚举、函数、闭包类型或模板参数作用域
(concept) |
|
(reflection TS)
|
指定元对象类型反映类型
(概念) |
|
(reflection TS)
|
指定元对象类型反映枚举项或常量表达式变量
(concept) |
|
(reflection TS)
|
指定元对象类型反映通过
get_base_classes
获取的直接基类
(概念) |
|
(reflection TS)
|
指定元对象类型反映函数形参
(concept) |
|
(reflection TS)
|
指定元对象类型反映函数(包括构造函数和析构函数)
(concept) |
|
(reflection TS)
|
指定元对象类型反映表达式
(concept) |
|
(reflection TS)
|
指定元对象类型反映括号表达式
(concept) |
|
(reflection TS)
|
指定元对象类型反映的是
function-call-expression
(concept) |
|
(reflection TS)
|
指定元对象类型反映
functional-type-conv-expression
(概念) |
|
(reflection TS)
|
指定元对象类型反映函数(不包括构造函数和析构函数)
(concept) |
|
(reflection TS)
|
指定元对象类型反映成员函数(不包括构造函数和析构函数)
(concept) |
|
(reflection TS)
|
指定元对象类型反映特殊成员函数
(概念) |
|
(reflection TS)
|
指定元对象类型反映构造函数
(concept) |
|
(reflection TS)
|
指定元对象类型反映析构函数
(concept) |
|
(reflection TS)
|
指定元对象类型反映运算符函数或转换函数
(concept) |
|
(reflection TS)
|
指定元对象类型反映转换函数
(concept) |
|
(reflection TS)
|
指定元对象类型反映非泛型lambda的闭包类型
(concept) |
|
(reflection TS)
|
指明元对象类型反映的是lambda捕获器
(concept) |
元对象操作
|
定义于头文件
<experimental/reflect>
|
|
|
定义于 命名空间
std::experimental::reflect
|
|
|
定义于内联命名空间
std::experimental::reflect::v1
|
|
|
|
|
(reflection TS)
|
检查两个元对象类型是否反映同一实体或别名
(类模板) |
|
(reflection TS)
|
获取被反射实体或别名的声明所在假定行号
(类模板) |
|
(reflection TS)
|
获取被反射实体或别名的声明在实现中定义的列号
(类模板) |
|
(reflection TS)
|
获取被反射实体或别名声明的假定文件名
(类模板) |
|
|
|
(reflection TS)
|
获取元对象序列的大小
(类模板) |
|
(reflection TS)
|
获取序列中指定索引的元对象类型
(类模板) |
|
(reflection TS)
|
将模板应用于元对象序列
(类模板) |
|
|
|
(reflection TS)
|
检查反射的实体或别名是否未命名
(类模板) |
|
(reflection TS)
|
获取反射实体或别名的非限定名称
(类模板) |
|
(reflection TS)
|
获取反射实体或别名的实现定义显示名称
(类模板) |
|
|
|
(reflection TS)
|
获取反映反射别名关联实体的元对象类型
(类模板) |
|
|
|
(反射TS)
|
获取反映被反射实体或别名类型的元对象类型
(类模板) |
|
(reflection TS)
|
获取反射实体或别名的类型
(类模板) |
|
(reflection TS)
|
检查元对象类型是否反映枚举类型
(类模板) |
|
(reflection TS)
|
检查元对象类型是否反映联合类型
(类模板) |
|
(reflection TS)
|
检查元对象类型是否反映使用
class
或
struct
分别声明的非联合类类型
(类模板) |
|
|
|
(reflection TS)
|
获取反映被反射实体或别名作用域的元对象类型
(类模板) |
|
|
|
(反射TS)
|
获取反映给定基类关系中基类的元对象类型
(类模板) |
|
|
|
(reflection TS)
|
检查反射的成员或基类是否为公开访问
(类模板) |
|
(reflection TS)
|
检查反射的成员或基类是否为受保护成员
(类模板) |
|
(reflection TS)
|
检查反射的成员或基类是否为私有
(类模板) |
|
|
|
获取一个元对象序列类型,其元素反映被反射类的公开、可访问或所有数据成员
(类模板) |
|
|
获取元对象序列类型,其元素反映被反射类的公开、可访问或所有成员函数
(类模板) |
|
|
(reflection TS)
|
获取一个元对象序列类型,其元素反映被反射类的所有构造函数
(类模板) |
|
(reflection TS)
|
获取元对象序列类型,其元素反映反射类中声明的所有运算符函数和转换函数
(类模板) |
|
(reflection TS)
|
获取反映被反射类析构函数的元对象类型
(类模板) |
|
获取一个元对象序列类型,其元素反映被反射类的公开、可访问或所有嵌套类型及成员类型定义
(类模板) |
|
|
获取一个元对象序列类型,其元素反映被反射类的公有、可访问或所有基类
(类模板) |
|
|
|
|
(reflection TS)
|
检查反射的枚举是否为作用域枚举
(类模板) |
|
(reflection TS)
|
获取一个元对象序列类型,其元素反映被反射枚举的枚举项
(类模板) |
|
(reflection TS)
|
获取反映被反射枚举底层类型的元对象类型
(类模板) |
|
|
|
(reflection TS)
|
获取作为常量表达式的反射变量的值
(类模板) |
|
(reflection TS)
|
检查变量是否声明为
thread_local
(类模板) |
|
|
|
(reflection TS)
|
检查反射参数是否具有默认实参
(类模板) |
|
|
|
(reflection TS)
|
获取元对象序列类型,其元素反映被反射函数的参数
(类模板) |
|
(反射 TS)
|
检查反射函数的参数列表是否包含省略号参数
(类模板) |
|
(reflection TS)
|
检查反射函数是否为非抛出函数
(类模板) |
|
(reflection TS)
|
检查被反射的函数是否被删除
(类模板) |
|
|
|
(reflection TS)
|
检查反射的变量或函数是否为 constexpr
(类模板) |
|
|
|
(reflection TS)
|
检查反射的命名空间或函数是否为内联
(类模板) |
|
|
|
(reflection TS)
|
获取反映带括号表达式的无括号表达式对应的元对象类型
(类模板) |
|
|
|
(reflection TS)
|
获取反映反射函数调用表达式中函数的元对象类型
(类模板) |
|
|
|
(reflection TS)
|
获取反映构造函数在反射式
functional-type-conv-expression
中的元对象类型
(类模板) |
|
|
|
(反射TS)
|
获取被反射变量或函数的地址,或指向被反射非静态成员的成员指针值
(类模板) |
|
|
|
检查被反射的成员函数是否分别声明了
const
、
volatile
、
&
或
&&
限定符
(类模板) |
|
|
(reflection TS)
|
检查反射的成员函数是否重写基类的成员函数
(类模板) |
|
|
|
(reflection TS)
|
检查反射的类或成员函数是否被标记为
final
(类模板) |
|
|
|
(reflection TS)
|
检查反射变量是否具有静态存储期,或反射成员函数是否为静态
(类模板) |
|
|
|
(reflection TS)
|
检查反射的特殊成员函数是否为隐式声明
(类模板) |
|
(reflection TS)
|
检查反射的特殊成员函数是否在其首次声明中被默认实现
(类模板) |
|
|
|
(reflection TS)
|
检查反射的构造函数或转换函数是否声明为
explicit
(类模板) |
|
|
|
(reflection TS)
|
检查反射的成员函数是否为虚函数
(类模板) |
|
(reflection TS)
|
检查反射的成员函数是否为纯虚函数
(类模板) |
|
|
|
(reflection TS)
|
获取元对象序列类型,其元素反映被反射闭包类型的捕获项
(类模板) |
|
(reflection TS)
|
检查反射闭包类型的lambda表达式的捕获默认值是否为
=
或
&
(分别对应)
(类模板) |
|
(reflection TS)
|
检查被反射的闭包类型的
operator()
是否声明为
const
(类模板) |
|
|
|
(reflection TS)
|
检查反射的lambda捕获是否为显式捕获
(类模板) |
|
(reflection TS)
|
检查反射的lambda捕获是否为初始化捕获
(类模板) |
库功能测试宏
|
定义于头文件
<experimental/reflect>
|
|
|
__cpp_lib_reflection
(reflection TS)
|
至少为
201902
的值表示支持反射TS的支持库
(宏常量) |
概念满足性
下表列出了反映操作数的元对象类型是否满足反射技术规范引入的概念。
| 类别 |
reflexpr
操作数
|
满足的概念 |
|---|---|---|
| 类型 | class-name 指定 union |
reflect::Union
|
| class-name 指定 closure type |
reflect::Lambda
|
|
| class-name 指定非联合类 |
reflect::Record
|
|
| enum-name |
reflect::Enum
|
|
| template type-parameter |
reflect::Type
,
reflect::Alias
|
|
| decltype-specifier |
reflect::Type
,
reflect::Alias
|
|
| type-name 通过 using-declaration 引入 |
reflect::Type
,
reflect::Alias
,
reflect::ScopedMember
|
|
| 其他任意 typedef-name |
reflect::Type
,
reflect::Alias
|
|
| 其他任意 type-id |
reflect::Type
|
|
| 命名空间 | namespace-alias |
reflect::Namespace
,
reflect::Alias
|
| 全局命名空间 |
reflect::GlobalScope
|
|
| 其他任意 namespace |
reflect::Namespace
|
|
| 表达式 | 数据成员名称 |
reflect::Variable
|
| 变量名称 |
reflect::Variable
|
|
| 枚举项名称 |
reflect::Enumerator
|
|
| 函数参数名称 |
reflect::FunctionParameter
|
|
| captured entity 名称 |
reflect::LambdaCapture
|
|
| 括号表达式 |
reflect::ParenthesizedExpression
|
|
| function-call-expression |
reflect::FunctionCallExpression
|
|
| functional-type-conv-expression |
reflect::FunctionalTypeConversion
|
如果形式为标识表达式的操作数是常量表达式,则通过reflexpr说明符指定的类型也满足
reflect::Constant
。
如果 reflexpr 操作数指定了类成员,则 reflexpr 说明符所表示的类型也满足
reflect::RecordMember
要求。
另请参阅
|
包含某些类型的信息,由 typeid 运算符返回的类
(类) |
|
|
(C++11)
|
编译时类型信息工具 |