C++ Aggregate & Macro Reflection
Relevant source files
The following files were used as context for generating this wiki page:
- include/HXLibs/reflection/ReflectionMacro.hpp
- include/HXLibs/reflection/EnumName.hpp
- include/HXLibs/reflection/TypeName.hpp
- include/HXLibs/reflection/MemberName.hpp
- tests/reflection/01_reflection.cpp
- tests/reflection/02_refl_macro.cpp
- tests/reflection/03_refl_enum.cpp
- tests/reflection/04_refl_typeName.cpp
The HXLibs reflection system provides compile-time metadata extraction for C++ structures, classes, and enumerations. It enables automated serialization, type introspection, and member iteration without requiring manual boilerplate for every field. The system supports two primary modes: automatic aggregate reflection for simple structs and macro-based reflection for classes with private members or custom naming requirements.
Sources: tests/reflection/01_reflection.cpp:1-20, tests/reflection/02_refl_macro.cpp:1-15
Core Reflection Capabilities
The library provides a set of template functions and constants within the HX::reflection namespace to query type information at compile time.
Aggregate Reflection
For standard C++ aggregate types, the system automatically detects the number of members and extracts their names. This process utilizes internal template metaprogramming (specifically internal::Any conversion operators) to probe structure definitions.
membersCount<T>(): Returns the number of fields in an aggregate struct as aconstexprvalue.getMembersNames<T>(): Returns aconstexprarray ofstd::string_viewcontaining the names of the fields.getMembersNamesMap<T>(): Generates a compile-time hash map (CHashMap) mapping field names to their respective indices.
Sources: tests/reflection/01_reflection.cpp:11-37, tests/reflection/01_reflection.cpp:110-120
Macro-Based Reflection
When types contain private members or require field aliases, macros are used to register metadata.
| Macro | Description |
|---|---|
HX_REFL(...) | Registers private members for reflection within a class scope. |
HX_REFL_AS(...) | Registers members with custom string aliases (e.g., a, "json_a"). |
HX_REFL_G(...) | Registers reflection metadata globally (outside the class definition). |
HX_REFL_G_AS(...) | Registers global reflection metadata with member aliases. |
Sources: tests/reflection/02_refl_macro.cpp:15-20, tests/reflection/02_refl_macro.cpp:55-60, tests/reflection/01_reflection.cpp:247-252
Architecture and Data Flow
The reflection system acts as a bridge between raw C++ types and higher-level utilities like JSON serializers or loggers.
The diagram shows how the system discovers metadata through two distinct paths and feeds it into utility functions.
Sources: tests/reflection/01_reflection.cpp:168-200, tests/reflection/02_refl_macro.cpp:25-45
Type and Member Introspection
Type Name Extraction
The reflection::getTypeName<T>() utility extracts the name of a class, struct, union, or enum as a string.
- It supports nested types but only returns the local name (no namespace prefixes).
- It correctly identifies types behind
usingaliases by resolving them to the original declaration. - Template types are supported, returning the base template name (e.g.,
ArrayforArray<int, 3>).
Sources: tests/reflection/04_refl_typeName.cpp:38-65, tests/reflection/04_refl_typeName.cpp:108-115
Enum Reflection
The EnumName.hpp header provides utilities for converting between enumeration values and their string representations.
toEnumName(value): Returns the string name of an enum constant.toEnum<T>(string): Converts a string back into the corresponding enum value.isValidEnumValue<T, Val>: Checks at compile time if a specific value is a valid member of the enum.getValidEnumValueCnt<T>(): Returns the total count of valid entries in the enum.
Sources: tests/reflection/03_refl_enum.cpp:10-35, include/HXLibs/reflection/EnumName.hpp
Member Iteration
The reflection::forEach function allows developers to iterate over all members of a reflective object. It accepts a lambda function that receives the member index, member name, and a reference to the member value.
reflection::forEach(obj, [] <std::size_t Idx> (std::index_sequence<Idx>, auto name, auto& value) {
// Process each member 'value' with its 'name'
});
Sources: tests/reflection/01_reflection.cpp:168-185, tests/reflection/02_refl_macro.cpp:27-42
Component Summary
| Component | Header | Primary Function |
|---|---|---|
| MemberName | MemberName.hpp | Provides membersCount and getMembersNames for aggregates. |
| ReflectionMacro | ReflectionMacro.hpp | Defines HX_REFL and HX_REFL_G families for explicit registration. |
| TypeName | TypeName.hpp | Implements getTypeName<T> for static type identification. |
| EnumName | EnumName.hpp | Provides bidirectional mapping between Enums and strings. |
Sources: include/HXLibs/reflection/ReflectionMacro.hpp, include/HXLibs/reflection/TypeName.hpp, tests/reflection/01_reflection.cpp:4-10
Conclusion
The C++ Aggregate & Macro Reflection module provides a zero-overhead mechanism for type introspection. By combining automatic aggregate detection with macro-based overrides, it supports a wide range of C++ types including those with private encapsulation. This system serves as the foundational metadata layer for the library's JSON serialization and logging frameworks.
Sources: tests/reflection/01_reflection.cpp, tests/reflection/02_refl_macro.cpp