C++26 reflection
reflect-cpp can be compiled in two modes, which use two different reflection implementations:
- C++-20/23 mode (the default): reflection is implemented using metaprogramming
techniques (structured bindings, aggregate-initialization analysis, and
enchantum). This works on a wide range of
compilers, but it has some limitations and comes with a higher compile-time cost.
- C++-26 mode: reflection uses the standard C++ reflection facilities
(
<meta>, P2996). This is more powerful, because members
and enumerators are queried directly from the compiler instead of being inferred.
C++-26 mode is opt-in. It requires a compiler that supports the C++ reflection proposal
and a compiler flag to activate it. The rest of this documentation applies to both modes,
except where explicitly noted otherwise.
Compiling with C++-26 reflection
The following compilers are supported for C++-26:
- GCC 16.2 or higher
- Clang: experimental, only available in Clang builds that implement
P2996 (such as Bloomberg’s
clang-p2996 fork)
To compile reflect-cpp with C++-26 reflection, pass the CMake option
REFLECTCPP_USE_CPP26_REFLECTION and the compiler flag that activates reflection
support in your compiler:
- GCC:
-freflection - Clang:
-freflection-latest
For example, using cmake:
cmake -S . -B build -DCMAKE_CXX_STANDARD=26 -DCMAKE_BUILD_TYPE=Release -DREFLECTCPP_USE_CPP26_REFLECTION=ON -DCMAKE_CXX_FLAGS="-freflection"
cmake --build build -j 4
The individual parts:
-DREFLECTCPP_USE_CPP26_REFLECTION=ON switches reflect-cpp to the C++-26 reflection
implementation and defines the macro REFLECTCPP_USE_CPP26_REFLECTION. If
CMAKE_CXX_STANDARD is not set, it will be set to 26 automatically.-DCMAKE_CXX_STANDARD=26 sets the C++ standard to 26.-DCMAKE_CXX_FLAGS="-freflection" activates the C++ reflection facilities in the
compiler itself. Use -freflection-latest on Clang instead.
When compiling with C++-26 reflection, the option REFLECTCPP_USE_STD_EXPECTED is
enabled by default as well, which means that rfl::Result<T> is an alias for
std::expected<T, rfl::Error>. If you want to keep using the built-in rfl::Result
type, pass -DREFLECTCPP_USE_STD_EXPECTED=OFF.
If you include the source files directly into your own build (see
Installation), add the
compile definition -DREFLECTCPP_USE_CPP26_REFLECTION and the appropriate compiler flag
to all translation units that include reflect-cpp.
What C++-26 reflection changes
C arrays and inheritance are supported out of the box
In C++-20/23 mode, fixed-size C arrays and inheritance are only supported when you pass
the flag -DREFLECT_CPP_C_ARRAYS_OR_INHERITANCE, and inheritance only works when all of
the fields are inside the same struct. Refer to
*C arrays and inheritance for details.
In C++-26 mode, neither restriction applies:
- Fixed-size C arrays are regular fields as far as the compiler’s reflection is concerned,
so they work without any flag.
- The fields of base classes are combined with the fields of the derived class, so the
fields may be spread out over multiple structs.
For example, this is not supported in C++-20/23 mode, but works as-is in C++-26 mode:
struct Base {
int x;
};
struct Derived : Base {
int y;
};
const auto derived = Derived{1, 2};
rfl::json::write(derived);
This results in the following JSON string:
No range restrictions for enums
In C++-20/23 mode, enum values must be in the range [RFL_ENUM_RANGE_MIN, RFL_ENUM_RANGE_MAX], where the default range is [-256, 256]. Refer to
*Enums for details.
In C++-26 mode, the enumerators are read directly from the compiler, so there is no
restriction on the range of enum values, and RFL_ENUM_RANGE_MIN and RFL_ENUM_RANGE_MAX
are not needed.
Lower compile-time cost
In C++-20/23 mode, reflect-cpp infers the fields of a struct by figuring out how the
struct can be constructed. This requires a lot of compile-time work, especially in the
presence of C arrays and inheritance. In C++-26 mode, the fields and enumerators are
queried directly from the compiler’s reflection information, which is considerably
cheaper.
Summary
| Feature | C++-20/23 | C++-26 |
|---|
| Supported compilers | GCC 11.4+, Clang 14.0+, MSVC 17.8+ | GCC 16.2+ (Clang: experimental) |
| Compiler flag | (none) | -freflection (GCC), -freflection-latest (Clang) |
| CMake option | (none) | -DREFLECTCPP_USE_CPP26_REFLECTION=ON |
| Fixed-size C arrays | requires -DREFLECT_CPP_C_ARRAYS_OR_INHERITANCE | supported out of the box |
| Inheritance | requires -DREFLECT_CPP_C_ARRAYS_OR_INHERITANCE, fields must be in a single struct | supported out of the box, fields may be spread over multiple structs |
| Enum value range | restricted to [RFL_ENUM_RANGE_MIN, RFL_ENUM_RANGE_MAX] (default [-256, 256]) | no restriction |
| Compile time | higher | lower |