Ch24: Reflection

中文(简体)

Why This Chapter Exists

C++ has always known more about your program than your program can ask. The compiler sees the member names, the field types, the enum constants, the base classes and the layout. Before C++26, none of that was available as a value. You wrote the serializer by hand, maintained a macro list, or ran an external generator.

C++26 reflection changes that. A program can reflect a type or a member into a std::meta::info value, query it with consteval functions, and splice the result back into source code. The same feature can complete an incomplete aggregate from a list of reflected members.

This chapter assumes no prior knowledge of reflection. It starts from the problem, teaches the C++26 model, writes real patterns (enum names, field visitors, JSON, generated types), and ends with the compiler support and adoption strategy. The code is C++26, not a library emulation; the last page explains what to do when your compiler does not have it yet.

The Four Pages

  1. 24.1 Why Reflection
  2. 24.2 The C++26 Reflection Model
  3. 24.3 Reflection in Practice
  4. 24.4 Support and Adoption

The Short Version

Reflection is a compile-time operation. ^^ turns a grammatical element — a type, a member, an enumerator, a namespace, a variable — into a reflection value of type std::meta::info. The std::meta namespace contains consteval functions that query those values: names, types, members, bases, enumerators, layout, properties. A splice [: r :] turns a reflection back into an expression, a type, a scope or a template argument.

template for is the expansion statement. It unrolls a loop at compile time, with a constexpr reflection per iteration. define_aggregate and data_member_spec complete an incomplete aggregate from a list of member descriptions. That is the generation half of the feature.

The mental model has four steps: reflect with ^^, query with std::meta, decide with ordinary if and loops, splice or generate. The control flow is normal C++ constexpr code. Only the data type and the splice syntax are new.

Reflection does not replace templates, and it is not runtime introspection. It removes the second declaration: the hand-written serializer, the enum switch, the macro table, the generated wrapper. It does not remove policy. Escaping, optional fields, versions, unknown keys and error handling are still design decisions.

C++26 has the feature, but compilers are still catching up. GCC 16 has an implementation; Bloomberg's Clang fork and EDG have implementations; upstream Clang and MSVC do not have a complete public implementation at the time of writing. Guard the feature with __cpp_impl_reflection, __cpp_lib_reflection and __cpp_lib_define_static, keep a fallback, and start with the smallest use case that pays for itself.

Key Takeaways