C++目前无原生编译期反射,所谓C++26静态反射仍处TS草案阶段,主流编译器均不支持;实际可用方案依赖宏+模板元编程(如Boost.PFR),需显式声明字段且须校验standard_layout。

编译期反射不是“运行时能查类型”,而是“编译时就知道结构”
它不是 Java 那种 obj.getClass().getFields() 的东西——C++ 标准至今(2026 年初)**没有落地的原生编译期反射**。所谓“C++26 静态反射”仍处于 TS(Technical Specification)草案阶段,reflexpr、std::reflect::fields() 等接口尚未进入 ISO C++ 标准,主流编译器(GCC 14 / Clang 18 / MSVC 19.39)均不支持。你在网上看到的示例代码,基本是基于提案文档的“概念性伪代码”,不能直接编译通过。
现在真能用的“编译期反射”,靠的是宏 + 模板元编程硬推
实际项目里想在编译期拿到字段名、类型、顺序,只能自己造轮子,核心是:用宏把字段列表展开成模板参数包,再用 constexpr 函数或变量模板提取信息。比如定义 REFLECT(Point, x, y),宏会展开为:
templateconstexpr auto field_name_v = []{ if constexpr (I == 0) return "x"; else if constexpr (I == 1) return "y"; }();
常见做法和注意事项:
- 必须每个类显式声明反射字段,
REFLECT(MyStruct, a, b, c)是强制契约,漏写就查不到 - 字段名不带类型前缀(如不写
"MyStruct.a")会导致跨类型冲突,比如两个类都有id字段,get_field_value(obj, "id")就会歧义 - 不能自动处理嵌套结构体或模板参数(如
std::vector中的T),需手动特化或限制为平凡类型 - Boost.PFR 是目前最成熟的轻量方案:它用
BOOST_PFR_REFLECT宏 +boost::pfr::members_count等接口,依赖编译器扩展(如 GCC 的() __builtin_types_compatible_p),但不支持私有成员、继承或虚函数
别把“运行时注册”当成编译期反射
像 rttr::registration::class_ 或手写 std::map<:string fieldinfo> 这类方案,本质是运行时构建元数据表,有内存占用、哈希查找开销,且字段访问需指针偏移计算(reinterpret_cast)。它们和“编译期反射”是两类东西:
立即学习“C++免费学习笔记(深入)”;
- 编译期方案:零运行时成本,但代码侵入强、调试难、IDE 支持差(字段名是字符串字面量,不参与符号索引)
- 运行时方案:字段可动态增删、支持调试器查看,但每次
get_property("x")都要查 map,序列化百万对象时性能差距明显 - 混合用法常见:用宏生成编译期字段列表(用于序列化/校验),再用运行时注册表支撑编辑器属性面板(需要 GUI 动态刷新)
C++26 的 reflexpr 到底离我们还有多远?
它确实已在 WG21 投票推进中,但落地节奏取决于编译器厂商——Clang 已在实验分支中实现部分 P0953 提案,GCC 尚未公开 roadmap,MSVC 明确表示“优先级低于模块和协程”。这意味着:
- 2026 年内指望它进生产项目,不现实;现有代码若强行依赖草案 API,大概率在 C++26 正式发布时被打破
- 当前最稳妥路径仍是:用 Boost.PFR 做数据结构反射,用
typeid+dynamic_cast做有限类型识别,关键逻辑(如网络同步字段)靠宏+静态断言兜底 - 真正容易被忽略的坑是:字段顺序依赖声明顺序,而 C++ 标准不保证结构体内存布局(尤其含 bitfield 或不同访问控制符时),
offsetof可能失效——必须加static_assert(std::is_standard_layout_v)
编译期反射的本质,是拿编译时间换运行效率,但代价是更复杂的构建流程和更脆弱的抽象边界。别急着等标准,先把你那个 struct Config { int port; std::string host; }; 用 BOOST_PFR_REFLECT 包起来,跑通单元测试再说。










