反射扩展
C++ 反射扩展,ISO/IEC TS 23619:2021,指定了对核心语言的修改,并定义了此页面上列出的 C++ 标准库的新组件。
反射 TS 基于 C++20 标准(除了概念的定义是按照 概念 TS 的风格指定)。
[编辑] 核心语言变更
[编辑] reflexpr-specifier
reflexpr-specifier 的形式为 reflexpr
(
reflexpr-operand )
,并指定元对象类型(见下文)。
reflexpr-operand 可以是以下之一
::
|
(1) | ||||||||
类型标识符 | (2) | ||||||||
嵌套名称说明符(可选) 命名空间名称 | (3) | ||||||||
标识符表达式 | (4) | ||||||||
( 表达式 ) |
(5) | ||||||||
函数调用表达式 | (6) | ||||||||
函数类型转换表达式 | (7) | ||||||||
其中 函数调用表达式 为
后缀表达式 ( 表达式列表(可选) ) |
|||||||||
而 函数类型转换表达式 是执行 显式转换 的以下类型的表达式
简单类型说明符 ( 表达式列表(可选) ) |
(1) | ||||||||
类型名称说明符 ( 表达式列表(可选) ) |
(2) | ||||||||
简单类型说明符 花括号初始化列表 | (3) | ||||||||
类型名称说明符 花括号初始化列表 | (4) | ||||||||
reflexpr-specifier 的操作数应为 类型、命名空间、枚举器、变量、数据成员、函数参数、捕获实体、函数调用表达式 或 函数类型转换表达式 以及带括号的表达式。 reflexpr(::) 反映全局命名空间。
对于形式为 (
表达式 )
的 reflexpr-operand,表达式 应为(可能带有多个括号的)函数调用表达式 或 函数类型转换表达式。
如果未带括号的操作数可以被视为 类型标识符 或 函数类型转换表达式,则将其视为 类型标识符。括号可以用于区分函数风格的转换和 类型标识符。例如,给定具有默认构造函数的类类型 X
,reflexpr(X()) 反映函数类型 X(),而 reflexpr((X())) 反映表达式 X()。
如果操作数同时指定别名和类名,则由 reflexpr-specifier 表示的类型反映别名并满足 reflect::Alias
。
如果操作数指定一个声明在块作用域内的名称,并且该命名实体既未被捕获也非函数参数,则程序格式错误。
[edit] 元对象类型
元对象类型 是一个无名、不完整的命名空间作用域类类型。一个类型满足概念 reflect::Object
当且仅当它是一个元对象类型。元对象类型可以满足其他概念,具体取决于 reflexpr
的操作数。
对于同一个操作数,重复应用 reflexpr
是否产生相同类型或不同类型是未指定的。如果一个元对象类型反映一个不完整的类类型,则无法应用某些类型转换。
元对象类型允许通过类型特征或对其进行类型转换来检查 reflexpr
操作数的某些属性。
[edit] 重载解析
如果 函数调用表达式 的 后缀表达式 为类类型,即 e 在 函数调用表达式 e(args) 中为类类型,则 后缀表达式 (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)); // error: conversion function used
[edit]
别名 是由 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, but not B::X or B::Y is reflection-related to D::Y
[edit] 其他
- 用作 reflexpr-operand 的表达式是一个 未求值表达式 并且 可能被常量求值。
- 为了确定捕获默认值在 lambda 表达式 中捕获的变量,
reflexpr
操作数不被认为是未求值的操作数。 - 由元对象类型
T
反映的静态 存储期 函数或变量被专业化 std::experimental::reflect::get_pointer<T> 使用,就好像通过获取命名该函数或变量的 id-表达式的地址一样。 - 可以存在多个元对象类型的定义,只要对该类型的所有操作都产生相同的常量表达式结果。
- 一个类型是 依赖的,如果它由 reflexpr-specifier 表示,并且操作数
[edit] 关键字
[edit] 预定义的特性测试宏
__cpp_reflection (反射 TS) |
至少为 201902 的值表示支持反射 TS (宏常量) |
[edit] 库支持
[edit] 概念
在头文件
<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) |
指定元对象类型反映一个成员函数(不包括构造函数和析构函数) (概念) |
(反射 TS) |
指定元对象类型反映一个特殊成员函数 (概念) |
(反射 TS) |
指定元对象类型反映一个构造函数 (概念) |
(反射 TS) |
指定元对象类型反映一个析构函数 (概念) |
(反射 TS) |
指定元对象类型反映一个运算符函数或转换函数 (概念) |
(反射 TS) |
指定元对象类型反映一个转换函数 (概念) |
(反射 TS) |
指定元对象类型反映一个非泛型 lambda 的闭包类型 (概念) |
(反射 TS) |
指定元对象类型反映一个 lambda 捕获 (概念) |
[edit] 元对象操作
在头文件
<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) |
检查被反射的命名空间或函数是否为内联的。 (类模板) |
| |
(反射 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 捕获是否为初始化捕获。 (类模板) |
[edit] 库功能测试宏
在头文件
<experimental/reflect> 中定义 | |
__cpp_lib_reflection (反射 TS) |
至少为 201902 的值表示支持反射 TS 的支持库。 (宏常量) |
[edit] 满足概念
下表列出了反映操作数的元对象类型是否满足反射 TS 引入的概念。
类别 | reflexpr 操作数 |
满足的概念 |
---|---|---|
类型 | 类名 指定一个 联合 | reflect::Union
|
类名 指定一个 闭包类型 | reflect::Lambda
| |
类名 指定一个非联合类 | reflect::Record
| |
枚举名 | reflect::Enum
| |
模板 类型参数 | reflect::Type , reflect::Alias | |
decltype-specifier | reflect::Type , reflect::Alias | |
类型名 由 using-declaration 引入 | reflect::Type , reflect::Alias , reflect::ScopedMember | |
任何其他 typedef-name | reflect::Type , reflect::Alias | |
任何其他 type-id | 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
|
如果 id-expression 形式的操作数是一个常量表达式,则 reflexpr-specifier 指定的类型也满足 reflect::Constant
。
如果 reflexpr-operand 指定一个类成员,则 reflexpr-specifier 表示的类型也满足 reflect::RecordMember
。
[edit] 另请参阅
包含一些类型的 信息,即 typeid 运算符返回的类。 (class) | |
(C++11) |
编译时类型信息实用程序 |