Your sandbox for C++26 static reflection. Clone, run one script, see output — no local LLVM install needed.
./reflect <file.cc> pulls a pre-built image from Docker Hub (sagardesd/reflectionbox:latest),
compiles your file inside a temporary container, and streams the output back to your terminal.
The image contains Bloomberg's clang-p2996 fork —
the only experimental compiler that supports P2996 reflection today.
Heads up: This compiler is experimental — Bloomberg's own words are "DO NOT use for production". Expect occasional crashes on complex programs.
Only Docker is required. VS Code is optional.
| Tool | Required for |
|---|---|
| Docker Desktop (or Docker Engine on Linux) | ./reflect and the devcontainer |
| VS Code + Dev Containers extension | Interactive editor inside the container (optional) |
git clone https://github.com/sagardesd/ReflectionBox
cd ReflectionBox
./reflect examples/reflection_demo.ccUsage: ./reflect <file.cc> [compiler-flags...] [-- binary-args...]
Examples:
./reflect examples/reflection_demo.cc
./reflect my_demo.cc -O2
./reflect my_demo.cc -freflection-latest
./reflect my_demo.cc -g -fsanitize=address,undefined
./reflect my_demo.cc -- --my-arg value
Image options (mutually exclusive):
(default) Pull sagardesd/reflectionbox:latest from Docker Hub (~1-2 min first time)
--build Build the image from source locally (~60-90 min, compiles LLVM)
Other:
--help Show this message
That's it — one command to compile and run. Here's what happens under the hood:
- First run — pulls
sagardesd/reflectionbox:latestfrom Docker Hub (~3 GB, takes 1-2 min depending on your connection). - Every subsequent run — the image is already cached locally, so it starts instantly.
- A temporary container spins up, compiles your file with
-std=c++26 -freflection -stdlib=libc++, runs the binary, streams output, and exits. Nothing is left running.
Want to build the image from source instead? Pass
--build:./reflect --build examples/reflection_demo.ccThis compiles LLVM/Clang from source inside Docker — expect 60-90 minutes on first build. Only needed if you want to modify the compiler or can't use the Docker Hub image.
Create any .cc file inside the repo:
// hello.cc
#include <meta>
#include <print>
struct Point { double x, y, z; };
enum class Color { Red, Green, Blue };
int main() {
std::println("Fields of Point:");
template for (constexpr auto m : std::meta::nonstatic_data_members_of(^Point)) {
std::println(" {}", std::meta::identifier_of(m));
}
std::println("Colors:");
template for (constexpr auto e : std::meta::enumerators_of(^Color)) {
std::println(" {}", std::meta::identifier_of(e));
}
}Run it from your host:
./reflect hello.cc[reflect] hello.cc
━━━ cpprun ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
source : hello.cc
flags : -std=c++26 -freflection -stdlib=libc++
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[1/2] Compiling…
✓ compiled (2s)
[2/2] Running…
━━━ output ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Fields of Point:
x
y
z
Colors:
Red
Green
Blue
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ exited 0
# Compile and run in one command (pulls image from Docker Hub on first use)
./reflect my_demo.cc
# Extra compiler flags
./reflect my_demo.cc -O2
./reflect my_demo.cc -freflection-latest
./reflect my_demo.cc -g -O0 -fsanitize=address,undefined
# Pass arguments to the compiled binary
./reflect my_demo.cc -- --input data.txt
# Build the image from source instead of pulling from Docker Hub
# WARNING: Takes 60-90 min on first build (compiles LLVM from source)
./reflect --build my_demo.ccHow it works:
- Without
--build(default): pullssagardesd/reflectionbox:latestfrom Docker Hub on first use (~3 GB, cached after that), spins up a temporary container, runscppruninside it, and exits. - With
--build: builds the image locally from theDockerfilein.devcontainer/. Use this only if you need to modify the compiler setup or can't access Docker Hub.
Open the folder in VS Code and click Reopen in Container when prompted. Then in the integrated terminal:
cpprun my_demo.cc
cpprun my_demo.cc -O2
cpprun my_demo.cc -freflection-latest
cpprun my_demo.cc -- --input data.txtOpen any .cc file and press Ctrl+Shift+B to compile and run it.
Compiler errors appear as clickable squiggles in the editor.
More variants via Ctrl+Shift+P → Run Task:
| Task | Extra flags |
|---|---|
| reflect: compile & run | (default) |
| reflect: compile & run -O2 | -O2 |
| reflect: compile & run (ASan + UBSan) | -g -O0 -fsanitize=address,undefined |
| reflect: compile & run (-freflection-latest) | -freflection-latest |
Applied automatically by cpprun and ./reflect:
| Flag | Purpose |
|---|---|
-std=c++26 |
Required for P2996 syntax |
-freflection |
Core reflection — ^T, [:e:], std::meta:: |
-stdlib=libc++ |
Required — system libstdc++ doesn't have <meta> |
Optional experimental extensions:
| Flag | Proposal | What it adds |
|---|---|---|
-fparameter-reflection |
P3096 | Reflect function parameters |
-fexpansion-statements |
P1306 | template for over ranges |
-fattribute-reflection |
P3385 | Reflect [[attributes]] |
-freflection-latest |
all of the above | Shorthand for everything |
ReflectionBox/
├── reflect # ⭐ Entry-point: pulls Docker image + compiles + runs your file
├── .devcontainer/
│ ├── Dockerfile # 2-stage build: LLVM from source → slim dev image
│ └── devcontainer.json # VS Code devcontainer config
├── .github/workflows/
│ └── publish.yml # CI: builds & pushes sagardesd/reflectionbox:latest to Docker Hub
├── .vscode/
│ └── tasks.json # Ctrl+Shift+B → cpprun on the open file
├── scripts/
│ ├── cpprun # Compile-and-run helper (on $PATH inside the container)
│ └── gen_compile_commands # Regenerates compile_commands.json for clangd intellisense
├── examples/
│ ├── reflection_demo.cc # Member names, enum names, generic struct printer
│ ├── part_1_demo.cpp # Struct introspection with define_static_array + template for
│ ├── json_deserializer.cc # Reflection-powered JSON → struct deserializer
│ └── json26_example.cc # Header-only JSON serializer/deserializer round-trip
├── json26.hpp # Reflection-powered header-only JSON library
└── tags # ctags file for editor navigation
After adding new .cc files, regenerate the clangd index inside the container:
gen_compile_commandsMost users never need to build — ./reflect pulls the pre-built image from Docker Hub in 1-2 minutes.
The table below only applies if you pass --build (which compiles LLVM from source locally):
| Resource | Requirement |
|---|---|
| Disk during build | ~20 GB |
| Final image size | ~3 GB |
| RAM | 8 GB min, 16 GB recommended |
| Build time | ~30 min on 16 cores, ~90 min on 4 cores |
- P2996 paper — the full reflection proposal
- Bloomberg clang-p2996 — the compiler this container builds
- Implementation status — what's supported, known bugs
- Compiler Explorer — online P2996 playground (select
clang (experimental P2996))