第24章:反射

English

为什么有这一章

C++ 一直知道比你程序能问到的更多。编译器看到成员名字、字段类型、枚举常量、基类和布局。在 C++26 之前, 这些都不能作为值使用。你手写序列化器、维护宏列表,或者运行外部生成器。

C++26 反射改变了这一点。程序可以把类型或成员反射成 std::meta::info 值,用 consteval 函数查询它,并把结果拼回源码。同一个特性还能从一组反射成员补全一个 不完整聚合体。

这一章不假设你有任何反射基础。它从问题开始,讲 C++26 模型,写真实模式(枚举名字、字段访问器、 JSON、生成类型),最后讲编译器支持和采用策略。代码是 C++26,不是库模拟;最后一页讲你的编译器 还没有它时怎么办。

四页

  1. 第24.1章:为什么需要反射
  2. 第24.2章:C++26 反射模型
  3. 第24.3章:反射实践
  4. 第24.4章:支持与采用

简短版本

反射是编译期操作。^^ 把文法元素——类型、成员、枚举值、命名空间、变量——变成 std::meta::info 类型的反射值。std::meta 命名空间包含查询这些值的 consteval 函数:名字、类型、成员、基类、枚举值、布局、属性。拼接 [: r :] 把反射变回表达式、类型、作用域或模板参数。

template for 是展开语句。它在编译期展开循环,每次迭代有一个 constexpr 反射。define_aggregate 和 data_member_spec 从一组成员描述补全不完整 聚合体。这是特性的生成那一半。

心智模型有四步:用 ^^ 反射,用 std::meta 查询,用普通 if 和循环决定,然后拼接或生成。控制流是普通的 C++ constexpr 代码。只有数据类型和拼接语法是新的。

反射不替代模板,也不是运行时自省。它删除第二份声明:手写序列化器、枚举 switch、宏表、生成的包装。 它不删除策略。转义、可选字段、版本、未知键和错误处理仍然是设计决定。

C++26 有特性,但编译器还在追赶。GCC 16 有实现;Bloomberg 的 Clang 分支和 EDG 有实现; 写作时上游 Clang 和 MSVC 没有完整的公开实现。用 __cpp_impl_reflection、 __cpp_lib_reflection 和 __cpp_lib_define_static 保护特性, 保留回退,从最小、最划算的用例开始。

要点