Experimental C++26 static reflection implementation demonstrating member lookup, type information, serialization, and property modification using P2996.
Research Context: This repository contains proof-of-concept code supporting academic research comparing P2996's compile-time reflection with Unreal Engine's runtime reflection system. For detailed analysyis, findings, and comparitive evaluation, see the full research paper.
This project expands on initial reflection comparisons. The baseline project focuses on fundamental reflection capabilities: member lookup, type information, JSON serialization, and dynamic property modification.
git clone https://github.com/liamcremers/ReflectionProject.git
cd ReflectionProject
./setup.sh
./build/Reflection
./watch.shThis demo requires libc++ (LLVM's C++ standard library) built with the P2996 compiler for reflection features to work. While theoretically possible on Windows, libc++ on Windows with clang-cl has significant build challenges and is not officially supported by default in LLVM builds. The pre-built toolchain in this repo was compiled on Linux and heavily inspired by this dockerfile.
p2996-install/Pre-built P2996 clang compiler with libc++ (7.3GB, saves hours of compilation)main.cppReflection examples showcasing P2996 capabilities highlighting:- Member lookup across struct hierarchies
- Runtime type information access
- Automatic JSON serialization/deserialization
- Dynamic property modification without macros
setup.shInstalls required dependencies and builds projectwatch.shMonitors input.json and runs project when change detected
This project explores C++ static reflection as proposed in P2996 and compares it with Unreal Engine's Header Tool (UHT) reflection system.
H1: P2996 offers cleaner syntax with reduced macro overhead compared to Unreal's reflection system
H2: P2996 cannot replicate Unreal Engine's dynamic runtime capabilities
H3: P2996 offers better compile-time type safety and error detection compared to UE's macro-based approach
This project evaluates how P2996 and Unreal Engine handle four core reflection capabilities:
P2996 Approach:
- Compile-time member enumeration via
nonstatic_data_members_of() - Type-safe access with splicing operators (
:[type_of(member):]) - Recursive reflection for nested aggregates
- No macro annotations required
- Using nlohmann to handle json
Unreal Engine Approach:
- Runtime UPROPERTY macros for member marking
- Built-in
FJsonObjectConverterfor string-to-struct conversion - Requires explicit markup on each member
- Automatic handling via reflection metadata
| Feature | P2996 | Unreal Engine | Notes |
|---|---|---|---|
| Member Lookup | ✓ | ✓ | Both enumerate struct members |
| Type Information | ✓ | ✓ | Both access member types at compile/runtime |
| Serialization | ✓ | ✓ | P2996 generic, UE requires converter |
| Property Modification | ✓ | ✓ | Both support dynamic value assignment |
| Runtime Type Creation | ✗* | ✗ | Neither creates structs from unknown schemas |
| New Member Introduction | ✗* | ✗ | Both locked at compile-time |
WSL Setup (Windows Users)
# In PowerShell
wsl --install
wsl
# Inside WSL
sudo apt update
git clone https://github.com/liamcremers/ReflectionProject.git ~/ReflectionProject
cd ~/ReflectionProject
./setup.sh
code --remote wsl+Ubuntu .
./watch.shwsl bash -c "git clone https://github.com/liamcremers/ReflectionProject.git ~/ReflectionProject && cd ~/ReflectionProject && bash setup.sh && bash watch.sh"Install Github CLI tool
(type -p wget >/dev/null || (sudo apt update && sudo apt install wget -y)) \
&& sudo mkdir -p -m 755 /etc/apt/keyrings \
&& out=$(mktemp) && wget -nv -O$out https://cli.github.com/packages/githubcli-archive-keyring.gpg \
&& cat $out | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
&& sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& sudo mkdir -p -m 755 /etc/apt/sources.list.d \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
&& sudo apt update \
&& sudo apt install gh -y
gh auth loginBuilding P2996 Compiler from Source
If you want to build the compiler yourself instead of using the pre-built version:sudo apt-get update && sudo apt-get install -y \
build-essential cmake ninja-build git python3 zlib1g-dev
git clone --depth=1 --branch p2996 https://github.com/bloomberg/clang-p2996.git p2996
cmake -S p2996/llvm -B p2996/build-llvm -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DLLVM_ENABLE_ASSERTIONS=ON \
-DLLVM_UNREACHABLE_OPTIMIZE=ON \
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \
-DCLANG_DEFAULT_CXX_STDLIB=libc++ \
-DLLVM_ENABLE_PROJECTS=clang
cmake --build p2996/build-llvm -j $(nproc) # Takes 2+ hours
cmake --install p2996/build-llvm --prefix $PWD/p2996-installBuilding P2996 Compiler with Docker
Using Docker provides an isolated build environment. This approach is based on the simdjson experimental_json_builder Dockerfile.
VS Code Setup (clangd)
Important: Disable C/C++ IntelliSense and use the P2996-built clangd for proper reflection support.
Add to .vscode/settings.json:
{
"clangd.path": "${workspaceFolder}/clangd",
"clangd.arguments": [],
"C_Cpp.intelliSenseEngine": "disabled",
}This ensures VS Code uses the P2996-aware clangd that understands reflection syntax.
- P2996R13 - Reflection for C++26
- Bloomberg Clang/P2996 Implementation
- Experimental_json_builder/Dockerfile
- more credits in the paper...
Note: This is research code exploring C++26 reflection proposals. Production use should await C++26 compiler availability and standard finalization.