#reflection
54 posts tagged #reflection.
Reflection can flag a dangling signature that GCC 16.2 does not warn about
A reflection lint of under 60 lines flags 3 of 5 declarations in a namespace on GCC 16.2: two return a view of a by-value owner, one returns a reference that can bind a temporary. For the view case GCC 16.2 gives no warning with -Wall -Wextra, a plain run prints garbage, and AddressSanitizer reports a heap use after free.
Replacing moc with reflection: 35 of 48 matrix rows match, and a class needs no macro
I listed 48 things moc processes or generates and gave each a verdict that a test must back. 35 rows are the same: 30 against a real moc's output, 5 by behaviour that moc cannot give. 7 differ in a stated way and 4 are not supported yet. A Qt class and a gadget now need no macro, because the base class finds the class through a default template argument.
Closing the known limits of the Qt observable models
The first post listed ten limits of the observable container and its Qt models. Three tests found real defects while closing them, a hash slowdown turned out to be code placement, and a row index made a change 42 to 125 times cheaper at large sizes.
The pre-Búzios mailing has 89 papers: contracts, undefined behaviour, profiles and function-body reflection
The 2026-10 WG21 mailing lists 89 documents for the Búzios meeting of 16 to 21 November. Five papers are worth reading first: the contracts reply P4433R0, the undefined-behaviour framework P3100R9, Herb Sutter's question about profile-defined behaviour, the first profiles implementation report, and a proposal to reflect function bodies. This post says which ones I read and which I only know by title.
Two problems confirmed by the spec's author, fixed in both bindings
The author of the container spec wrote that section 8.3 is a mistake, not a trade-off, and that the lazy row map is in the real code. Both generated bindings now announce a batch removal while the entries still exist and find a row by binary search: a hash drain at 10,000 entries went from 193 microseconds per removal to 320 nanoseconds.
Deriving equality, hashing, and ordering from structure
C++20 gave us `= default` for operator== and <=>. Reflection lets us do the same for hashing, plus go beyond default: include/exclude fields, custom combinators, and floating-point tolerances. All declarative.
Naming a constant makes GCC stop believing it is one
A C++26 expansion statement over a compile-time range works on GCC 16.1 when the range is written inline and fails when the identical expression is given a name. The error says the constexpr variable is not a constant. Clang accepts both, and the workaround is to delete the name.
228 Qt model edge cases, and the ones my models failed
I wrote down 228 edge cases for the observable Qt models and tested each one. 170 work, 22 are refused on purpose, 27 were defects that are now fixed, and 9 are still pinned. The defects included an editor that writes an empty value back, and a model that survives its container with stale rows.
Regenerating a Qt container library from a spec, with and without moc
A reader wrote their observable Qt containers down as a spec an AI agent can regenerate from. Two fresh agents built it, one with classic moc and one with typed signals through reflect-moc. Both pass all 17 acceptance entries, the moc version builds with MSVC, and the spec itself has a row lookup that costs 193 microseconds per removal at 10,000 entries.
One Qt class template can declare typed signals without moc
A Qt engineer named reflect-moc's last open limit as exactly his case: one observable container for many types, which moc cannot give signals. The cause was one line. Now one container template declares typed signals, one generic model serves seven Qt containers, and a random test with six wrong adapters and 31 mutants checks that ghost rows and ghost selections cannot come from it.
Replaying Qt Bridges' meta-object calls in C++ and diffing them against moc
Qt Bridges' Rust layer builds each class's meta-object at run time with Qt's private QMetaObjectBuilder. I replayed its builder calls on one class in C++ and compared the result with what moc generates, on Qt 6.10.3, 6.11.3 and 6.12.0. The registration API has no way to say that a property is read-only, to name a signal's parameters or to add an enum, and in the C++ analogue emitting a signal by name costs about 22 to 46 ns more than emitting it by index. Source commits, line numbers, measurements and what was not run are listed.
C++26 reflection runs on a compiler you already have
The received wisdom is that trying P2996 means the Bloomberg clang fork. It does not. GCC 16.1 has shipped reflection since April behind -freflection, using the standard <meta> header, and it runs the same code. The two implementations do disagree about what display_string_of prints.
Four official Qt examples build and run without moc
Four examples from Qt 6.10.3 (a QThread renderer, a QML tutorial, a widgets example and a queued custom type) were rewritten by a migration tool and built with AUTOMOC off. Each prints the same harness output as the moc build, with 0 warnings, and a build in which moc is replaced by a failing trap passes. The diffs are 14 to 111 changed lines, the tool left nothing for manual work, and the limits and the timing noise are listed.
Parsing your config file before the program exists
#embed puts a file into the translation unit and reflection enumerates a struct's fields. Together they turn a configuration file into a compile-time constant, with the keys derived from the struct rather than written twice, and a missing entry becoming a build error rather than a failed startup.
Signals, slots and thread affinity without Qt or moc
The core of reflect-moc is signals, slots, queued and blocking connections, thread affinity and a per-thread event loop in plain C++26 with no Qt. A worker thread reports progress to an object on the main thread, and the program runs on Compiler Explorer. Under ThreadSanitizer the 18 core tests passed in the recorded run, and one test reports in 27 of 11000 repeats, a report that a 12-line std::latch program without the library also gets and that a mutex and condition variable removes.
A Q_OBJECT that never names its class
RQT_OBJECT is written like Q_OBJECT: no class name, no base class template, no registration call. It finds its class by asking std::meta::current_function() for its parent from inside member functions defined in the class body. RQT_PROPERTY takes the exact Q_PROPERTY text, stringifies it and parses it with a consteval function, so a misspelled keyword stops the build with a message. A Qt-free reduction of both runs on Compiler Explorer.
A tiny ORM: struct to SQL via reflection
Diesel / Entity Framework ergonomics in C++: annotate a struct, generate CREATE TABLE, SELECT, INSERT, UPDATE, and a row-to-struct binder. No codegen tool, no intrusive macros.
C++26 cannot write a signal's body, so a signal became a data member
A Qt signal is a function whose body moc generates, and C++26 reflection cannot generate a function body. A callable data member does not connect, a source_location tag gives every signal the same type, and a closure tag has internal linkage. What held is a bodyless data member that finds its owner through a hidden first member: 8 bytes per signal and 8 per class, measured. A static signal costs 0 bytes and has one silent pitfall. A signal that writes its own one-line body costs nothing and is the one form for overloaded signals.
EDG's C++ front end is open source, and Compiler Explorer builds it with reflection
The EDG C++ front end went open source on 30 September under the Apache 2.0 licence with LLVM exceptions, with the C++ Alliance as fiscal sponsor. Compiler Explorer added EDG 7.0 and trunk builds with P2996 reflection switched on the same day. One struct-walking snippet gives the same output on EDG, GCC 16.2 and clang-p2996 apart from one type spelling, and EDG rejects template for.
Qt accepts a QMetaObject that C++26 reflection built
Qt 6.10 builds its meta-objects from constexpr tables, so a table made by C++26 reflection goes in the same place. Stock Qt connects, invokes, reads properties of, casts to and binds in QML a class that moc never saw, and a differential test finds its QMetaObject identical to the one moc generates. Four things had to be worked around, and a signal's declaration had to change.
One function that fills any struct from any pattern
A regex with N captures already describes a record with N fields, and C++26 reflection can enumerate a struct's fields. Joining them gives a parse_into<T, Pattern>() that fills any aggregate with no per-struct code, which builds and runs today on the reflection fork.
reflect_soa: AoS → SoA → AoSoA, one struct, three layouts
Corrected on 6 October 2026: reflect_soa is not a published library (its repository holds only a README), the embedded demo is a reduced hand-written stand-in, and the benchmark timings were never measured and are removed. The correction at the top has the details; the rest is kept as published.
Reflection across languages: C++26 vs Rust, C#, Java, TypeScript, Go, Python
Capstone: the canonical reflection tasks — serialize, enum↔string, CLI parsing, ORM row binding — side by side in seven mainstream languages. Where C++ lands, and what the uniquely-C++ angle actually gives you.
When two enumerators share a value, the value carries both names
With red = 1 and green = 1, a reflection-based enum_to_string(green) returns "red", because once the value is in a variable nothing distinguishes the two. C++26 reflection can list every name for a value, reject duplicates at compile time with std::meta::exception, prefer a canonical spelling through an annotation, and keep the exact name when you reflect the enumerator itself. The names come back as string_views over static storage, so none of this allocates.
Replacing Qt's MOC with reflection
Qt's Meta-Object Compiler parses Q_OBJECT/Q_PROPERTY declarations and emits glue code. With C++26 reflection, Q_PROPERTY-equivalent becomes a library pattern — no external compiler, no generated files.
define_aggregate: synthesising types at compile time
TypeScript's Pick, Omit, and Partial have direct C++26 equivalents. define_aggregate lets you construct a new type from a list of member specs — opening up type-level programming that was previously pure metaprogramming wizardry.
Auto-generated mocks from interfaces
Corrected on 5 October 2026: reflection cannot generate the mock class this post describes, because define_aggregate adds data members and no functions. The correction at the top has the GCC errors; the rest is kept as published.
Autowired dependency injection: no container, just reflection
Spring's and .NET's DI containers, reimplemented as a 60-line C++26 library. Reflect constructor parameters, resolve them from a type registry, compose.
Clap for C++: turning structs into command-line parsers
Rust's clap-derive in C++: declare a struct, get a working argv parser with --flags, -short options, help text, subcommands. One attribute per field, zero manual dispatch.
One codegen, many wire formats
JSON, YAML, XML, TOML, MessagePack — all from the same annotated struct. Factor format-specific syntax into a policy object, share the reflection walk, ship N formats for the cost of one.
Deserialization and std::expected: completing the round-trip
Parse JSON into a typed C++ struct with precise per-field error reporting via std::expected. Reflection + template for + annotations — the same machinery, just running the other way.
Annotations: tag-driven serialization comes to C++
P3394 brings serde-style and Jackson-style attribute programming to C++: rename, skip, skip_if_empty, rename_all — all as plain user-defined values queryable by reflection.
A 40-line JSON serializer with reflection
Corrected on 6 October 2026: there is no reflect_json library, and the speed figures in the first version were not measured with a method I can show. The post walks a struct and emits JSON in about fifty lines, with no macros and no external codegen; the corrected measurement is in the Runtime cost section.
Defaulting a destructor costs you both move operations
Howard Hinnant's table tells you which special member functions survive once you declare one yourself. C++26 reflection can check it rather than trusting it, and the result for a defaulted destructor is the one worth internalising: a line that looks like a no-op removes move construction and move assignment.
reflect_tracing: zero-overhead spans on Maciek Gajewski's ring-buffer engine
Corrected on 6 October 2026: the library this post describes has not been published, and the timing figures in it were never measured. The note at the top says what the repository holds and what the embedded demo does. The rest is kept as published.
reflect_telemetry: compile-time Prometheus metrics from annotated fields
Corrected on 6 October 2026: the library this post describes has not been published, and its benchmark numbers were never measured. The note at the top says what the repository holds, what the embedded demo does and which code was fixed. The rest is kept as published.
reflect_dx: auto-generated debugger pretty-printers and docs
Corrected on 6 October 2026: reflect_dx is not a published library (its repository holds only a README), the two tools in this post do not exist, and reflection cannot read comments. The one working piece is a natvis snippet walk, which the embedded demo runs. The correction at the top has the details; the rest is kept as published.
Define your own function colors: compile-time caller checks with C++26 reflection
C++ already enforces function colors -- consteval, CUDA's __device__, Clang's [[clang::nonblocking]] -- but every one of them needed a compiler change. C++26's std::meta::current_function() (P3795R1) lets a callee reflect on its caller at compile time, so you can paint your own colors as a 20-line library: audio-thread safety, capability tokens, or architectural layers that refuse to compile when called from the wrong place. Here is the pattern, three professional uses, and exactly where it breaks.
reflect_optics: Haskell-style lenses for C++26
Corrected on 6 October 2026: reflect_optics is not a published library (its repository holds only a README), the embedded demo is a reduced stand-in with no pipe operator, and several code claims did not hold as written. The correction at the top has the details and the GCC results; the rest is kept as published.
Reflection + annotations for hashing: opt out of fields, not whole structs
Krystian Piekos's May 29 post on infotraining.pl shows the cleanest demo so far of P3394 annotations combined with P2996 reflection: opt structs into hashing with [[=hashable]], and opt individual fields out with [[=skipped_for_hash]]. The Hashable concept and the calculate_hash walker fit in 40 lines. No macros.
reflect_arbitrary: property-based test generators, inferred from your types
Corrected on 6 October 2026: reflect_arbitrary is not a published library (its repository holds only a README), the embedded demo is a reduced stand-in with a fixed-range random generator, and the printed shrinking output came from no test and is removed. The correction at the top has the details; the rest is kept as published.
reflect_llmschema: C++ functions to LLM tool-use schemas, at compile time
Corrected on 6 October 2026: reflect_llmschema is not a published library (its repository holds only a README), and the embedded demo is a reduced stand-in that prints a smaller JSON than this post shows. The correction at the top has the details and the real output; the rest is kept as published.
The fastest JVM is the C++26 compiler
Koen Samyn's BeCPP talk used std::meta::substitute to transform Java bytecode into executable C++ at compile time. The compiler constant-folds the entire program. The loop doesn't run faster. It doesn't exist. This is reflection used not for serialization or enum-to-string, but as a compile-time metaprogramming substrate for building language interpreters.
Revzin at C++Now: 'Reflection Is Only Half the Story' -- what generation looks like next
Barry Revzin's C++Now 2026 keynote (Mon 4 May, Aspen) landed the line the C++ reflection community has been circling for two years: C++26 reflection lets you OBSERVE -- the next question is what it looks like to GENERATE. The 90-minute talk is a tour of source-code-generation design space (macros, templates, Rust proc-macros, Swift macros, D mixins) and reads as the natural sequel to wro.cpp's whole 'Where this is heading' triptych framing.
The five most useful things C++26 reflection unlocks (in effort order)
C++26 reflection looks like it requires a PhD in template metaprogramming. It does not. Five concrete projects you can build with it, ranked from five minutes to weeks. Use this as a triage when picking your first reflection-powered project.
Is std::vector consteval or constexpr? A reader's question, answered
A colleague asked: 'Is std::vector consteval and not constexpr?' Short answer: no, but the intuition is right. Long answer: the constexpr/consteval/constinit trio, the transient-allocation rule, and why std::define_static_array exists.
Auto-generating std::formatter<T> for any aggregate
Rust's #[derive(Debug)] in C++: make any struct printable via std::format and std::println by dropping in one partial specialisation of std::formatter. Nested types, containers, enum names — all handled.
Goodbye magic_enum: enum reflection done right
A reflection-driven enum↔string library in 30 lines. No __PRETTY_FUNCTION__ tricks, no compile-time range knob, no compiler-specific behaviour — and unbounded, including enum values beyond 128.
GCC 16.1 ships C++26 reflection -- your 30-line hands-on
GCC 16.1 dropped on 30 April 2026 with -freflection. C++26 was finalized at Croydon five weeks earlier. Here is a 25-line program you can compile and run today on your laptop.
template for: iterating reflections at compile time
Expansion statements (proposal P1306) unroll a loop at compile time, instantiating the body once per element. They are the natural partner of reflection — one loop, N specialisations.
C++26 is done -- five weeks since Croydon, here's what shipped
Five weeks ago WG21 voted C++26 to publication in Croydon. The dust has settled enough to take stock of what landed, what compiles today, and what it means for the wro.cpp reflection series.
Splicing: [: r :] and putting reflections back into code
Splicing is the inverse of ^^: it takes a std::meta::info and drops the referred entity back into your source. Types, expressions, template arguments, member accesses — all round-trippable.
Your first ^^: reflecting types and walking members
Hands-on introduction to C++26 reflection: the ^^ operator, std::meta::info, and walking struct members. We take the post-1 teaser apart and rebuild it from primitives.
C++26 Reflection: What changes, and why it matters
Part 1 of the C++26 reflection series. A 40-line JSON serializer nobody could write in C++ before 2026 — plus the strategic story of why static reflection changes the ecosystem.