Extensions for reflection
C++反射扩展技术规范(ISO/IEC TS 23619:2021)规定了核心语言的修改,并定义了本页所列的C++标准库新组件。
反射技术规范基于 C++20 标准(除概念定义采用 概念技术规范 风格进行规定外)。
核心语言变更
reflexpr 说明符
一个
反射表达式说明符
的形式为
reflexpr
(
反射表达式操作数
)
,用于指定元对象类型(详见下文)。
reflexpr-operand 可以是以下之一:
::
|
(1) | ||||||||
| 类型标识 | (2) | ||||||||
| 嵌套名称说明符 (可选) 命名空间名称 | (3) | ||||||||
| 标识表达式 | (4) | ||||||||
(
表达式
)
|
(5) | ||||||||
| 函数调用表达式 | (6) | ||||||||
| 函数式类型转换表达式 | (7) | ||||||||
其中 function-call-expression 是
后缀表达式
(
表达式列表
(可选)
)
|
|||||||||
和 functional-type-conv-expression 是执行 显式转换 的以下类型表达式:
简单类型说明符
(
表达式列表
(可选)
)
|
(1) | ||||||||
类型名说明符
(
表达式列表
(可选)
)
|
(2) | ||||||||
| 简单类型说明符 花括号初始化列表 | (3) | ||||||||
| 类型名说明符 花括号初始化列表 | (4) | ||||||||
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)); // 正确 // 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是由 functional-type-conv-expressionA指定的类型, -
B是通过重载解析为 function-call-expressionA选定的函数, -
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,而非 B::X 或 B::Y 与 D::Y 存在反射关联
杂项
- 用作 reflexpr-operand 的表达式是 未求值表达式 且属于 潜在常量求值 。
-
为确定通过捕获默认方式
在 lambda 表达式中捕获的变量
时,
reflexpr操作数不被视为未求值操作数。 -
通过元对象类型
T反射的静态 存储期 函数或变量会被特化 std :: experimental :: reflect :: get_pointer < T > 进行 odr-use ,其方式类似于通过取命名该函数或变量的标识表达式地址。 - 元对象类型可以存在多个定义,只要对该类型的所有操作产生相同的常量表达式结果即可。
- 若类型由 reflexpr 说明符表示且其操作数满足以下条件,则该类型为 依赖类型 :
关键词
预定义功能测试宏
|
__cpp_reflection
(reflection TS)
|
值至少为
201902
表示支持反射技术规范
(宏常量) |
库支持
概念
|
定义于头文件
<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)
|
指定元对象类型反射成员函数(不包括构造函数和析构函数)
(概念) |
|
<a href="reflect
|
|
元对象操作
|
定义于头文件
<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)
|
获取反映被反射别名关联实体的元对象类型
(类模板) |
|
|
|
(reflection TS)
|
获取反映被反射实体或别名类型的元对象类型
(类模板) |
|
(reflection TS)
|
获取被反射实体或别名的类型
(类模板) |
|
(reflection TS)
|
检查元对象类型是否反映枚举类型
(类模板) |
|
(reflection TS)
|
检查元对象类型是否反映联合体类型
(类模板) |
|
(reflection TS)
|
检查元对象类型是否反映使用
class
或
struct
声明的非联合类类型
(类模板) |
|
|
|
(reflection TS)
|
获取反映被反射实体或别名作用域的元对象类型
(类模板) |
|
|
|
(reflection TS)
|
获取给定基类关系中反映基类的元对象类型
(类模板) |
|
|
|
(reflection TS)
|
检查被反射成员或基类是否为公开
(类模板) |
库特性测试宏
|
定义于头文件
<experimental/reflect>
|
|
|
__cpp_lib_reflection
(reflection TS)
|
值至少为
201902
表示支持反射技术规范的支持库
(宏常量) |
概念满足性
下表列出了反映操作数的元对象类型是否满足反射技术规范引入的概念。
| 类别 |
reflexpr
操作数
|
满足的概念 |
|---|---|---|
| 类型 | 类名 指代 联合体 |
reflect::Union
|
| 类名 指代 闭包类型 |
reflect::Lambda
|
|
| 类名 指代非联合体类 |
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)
|
编译时类型信息工具 |