| ▲ | Cost of enum-to-string: C++26 reflection vs. the old ways(vittorioromeo.com) |
| 36 points by sagacity 6 hours ago | 43 comments |
| |
|
| ▲ | jsd1982 an hour ago | parent | next [-] |
| I think the conclusion section should indicate that they are based entirely on GCC 16's behavior and current implementation. We should avoid generalizing one compiler's behavior and performance. Curious how this same test would behave once clang ships C++26 reflection. |
| |
| ▲ | SuperV1234 16 minutes ago | parent | next [-] | | I explicitly mentioned that GCC 16.1 was the compiler used in the benchmarking section, do you think I also need to add a disclaimer in the conclusion section as well? Regardless, I don't think things are going to differ much with Clang. Without PCH/modules, standard header inclusion is still the "slow part" of C++ compilation, regardless of the compiler used and the standard library used (libstdc++ vs libc++). `#include` is fundamentally the same on any modern compiler. Because the reflection feature itself seems quite fast on GCC (compared to the cost of the header), I predict the results will be similar on Clang as well. | |
| ▲ | bluGill an hour ago | parent | prev [-] | | I was thinking the same thing. Modules are still not widely used, it is a reasonable guess that there are a lot of optimization opportunities left. | | |
| ▲ | SuperV1234 14 minutes ago | parent [-] | | That is true, but on the other hand Modules were standardized more than 6 years ago. Promises and claims have been made for longer than that on how Modules would have improved compilation times and made everyone's lives easier. In 2026, I still have to see any real evidence of that, especially when PCH + unity builds are much easier to use (except on damn Bazel, which supports neither) and deliver great results. If after 6+ years of development Modules are still so far behind, it is fair to question if the problem is with the design/implementability of the feature itself. |
|
|
|
| ▲ | dataflow 14 minutes ago | parent | prev | next [-] |
| I don't see how a library like Enchantum could handle everything reflection does. (How) does it figure out duplicate enum values, for example? And (how) does it discover arbitrarily large, discontiguous ranges? And (how) does it do these on MSVC? |
| |
|
| ▲ | w4rh4wk5 3 hours ago | parent | prev | next [-] |
| I've been wondering about debug-ability of code using reflection. X-Macros are quite annoying to step through in most debuggers, though possible. While the code in the first example is evaluated fully at compile-time, how would you approach debugging it? |
| |
| ▲ | SuperV1234 10 minutes ago | parent | next [-] | | Nothing that makes it straightforward. Testing via `static_assert` is a good strategy, but it's not debugging. I believe there are some ways of printing custom diagnostics during compilation, but I am not aware of any step-by-step debugging tool that runs at compile-time. In practice, I haven't really needed to ever debug `consteval` functions -- it's quite easy to get the right behavior down thanks to `static_assert`-based testing and thanks to the fact that they do not depend on external state (simpler). | |
| ▲ | cenamus 2 hours ago | parent | prev [-] | | I mean it's still C++ that's compiled and executed, surely the compiler would be able to provide a way to hook into that? | | |
| ▲ | usefulcat 38 minutes ago | parent [-] | | I don't recall the source, but I don't believe most (any?) c++ compilers implement compile-time code evaluation by compiling and running code. For one thing they are required to disallow all undefined behavior for compile time execution, and some forms of UB only occur when the code is run. |
|
|
|
| ▲ | randusername 2 hours ago | parent | prev | next [-] |
| I can't imagine myself using reflection much, but maybe it will eliminate a lot of feature proposals bogging down the committee and they can focus on harder problems. It would be cool if the stated goal of C++29 was compile times. |
| |
| ▲ | w4rh4wk5 an hour ago | parent [-] | | I'd argue reflection is very much a feature for libraries. You wouldn't use it directly, but your JSON / YAML serialize is then built on top of it. So are your bindings for scripting engines like Lua. | | |
| ▲ | SuperV1234 13 minutes ago | parent | next [-] | | You can already automatically serialize/deserialize arbitrarily nested structs since C++17 (using Boost.PFR). Since C++20, you can also serialize/deserialize the struct data member names automatically. For many useful use cases, you don't need C++26 reflection at all. E.g. https://www.linkedin.com/posts/vittorioromeo_cpp-gamedev-ref... | |
| ▲ | bluGill an hour ago | parent | prev | next [-] | | There are a lot of things that are very very important for a tiny niche. In any non-trivial project you will end up with a lot of custom libraries and some of them really benefit from some obscure feature that no place else in your project would want. | |
| ▲ | agentultra 39 minutes ago | parent | prev [-] | | Also nice for UI tooling; game tools, debuggers, etc. Pull apart a struct and display it on screen and not have to patch the UI tool every time you change the struct is pretty nice. | | |
|
|
|
| ▲ | HarHarVeryFunny 2 hours ago | parent | prev | next [-] |
| No doubt reflection has been built with other use cases in mind, but it sure would have been nice just to have std::to_string(enum) |
| |
| ▲ | bluGill 2 hours ago | parent [-] | | C++ conference speakers (including keynotes) are now begging everyone to stop using enum to string in their example. While they are a simple and easy to understand example, reflection is for much more interesting problems. I can't think of any other example that I would type into a comment box or put on a slide. | | |
| ▲ | maccard an hour ago | parent | next [-] | | Serialization is the canonical example. Being able to turn struct MyStruct {
int val = 42;
string name = "my name";
};
into {
"val": 42, // if JSON had integers, and comments of course
"name": "my name",
}
is incredibly powerfuly. If reflection supported attributes (i can't believe it shipped without, honestly), then you could also mark members as [[ignore]] and skip them. | | |
| ▲ | SuperV1234 9 minutes ago | parent | next [-] | | You can achieve that since C++20 (or C++17 if you don't care about the member names). E.g. https://www.linkedin.com/posts/vittorioromeo_cpp-gamedev-ref... (The link above shows ImGui generation, but the same exact logic can be applied for serialiation to JSON/YAML/whatever.) | |
| ▲ | bluGill 31 minutes ago | parent | prev [-] | | It is powerful, but I'm not sure it is a good idea. Other languages have it, and there is lots of experience in all the ways things go wrong in the real world. I'm inclined to say you should hand write this code because eventually you will discover something weird anyway. | | |
| ▲ | electroly 8 minutes ago | parent | next [-] | | Can you give an example of a language ecosystem that went with reflection-based JSON serialization/deserialization and then went on to regret it? I can't think of any, and don't agree with your conclusion. It works great, and manually writing serialization and matching deserialization code is terrible, annoying, error-prone work. | |
| ▲ | SuperV1234 8 minutes ago | parent | prev [-] | | I think this is a very bad take -- once you write it by hand you have to manually keep it in sync with the actual struct and ensure you made no mistakes. Reflection guarantees 1-1 future-proof mapping with the actual C++ struct, avoids boilerplate, and ensures that the serialization logic is correct. |
|
| |
| ▲ | cogman10 an hour ago | parent | prev | next [-] | | It comes up pretty frequently in java. Serialization/Deserialization, adding capabilities based on type, Adding new capabilities to a type, general tuning (for example, adding a timing or logging call onto methods). Almost all the Java web frameworks are giant balls of reflection. Name a function the right way or add the right magic annotation and the framework will autowire it correctly. It's a pretty powerful tool. (IDK if C++'s reflection is as capable, but this is what was enabled by java's reflection). | | |
| ▲ | SuperV1234 7 minutes ago | parent | next [-] | | Java reflection is another beast altogether as it is runtime reflection. C++26 reflection is purely compile-time, which not only means it adds zero runtime cost, but also prevents those kind-of-insane use cases you see in Java and C#. | |
| ▲ | david422 44 minutes ago | parent | prev [-] | | > Almost all the Java web frameworks are giant balls of reflection. Name a function the right way or add the right magic annotation and the framework will autowire it correctly. I find this to be very powerful, and also very unintuitive/undiscoverable at the same time. | | |
| ▲ | cogman10 12 minutes ago | parent | next [-] | | Initially, but it very quickly becomes discoverable once you are familiar with how things are working. Most frameworks in Java are very similar. The ones that aren't are effectively doing what "expressjs" does in terms of setup, which is still pretty discoverable. Most java frameworks rely on annotations rather than naming schemes which makes everything a lot easier to grok. | |
| ▲ | kuboble 13 minutes ago | parent | prev [-] | | Reflection is simply a syntax vinegar for duck typing. |
|
| |
| ▲ | surajrmal 2 hours ago | parent | prev [-] | | Anybody the derive traits rust has are a good demo. |
|
|
|
| ▲ | mentos 27 minutes ago | parent | prev | next [-] |
| Curious to see if Epic Games ever refactors their reflection in Unreal Engine to use C++ 26 reflections or not. |
|
| ▲ | sagacity 6 hours ago | parent | prev | next [-] |
| Oof, that first example (the idiomatic C++26 way) looks so foreign if you're mostly used to C++11. |
| |
| ▲ | delegate 24 minutes ago | parent | next [-] | | I was very curious to see what C++ 26 brings to the table, since I haven't used C++ in a while. When I saw the 'no boilerplate' example, the very first thought that came to my mind: This is the ugliest, most cryptic and confusing piece of code I've ever seen.
Calling this 'no boilerplate' is an insult to the word 'boilerplate'. Yeah, I can parse it for a minute or two and I mostly get it. But if given the choice, I'd choose the C-macro implementation (which is 30+ years old) over this, every time. Or the good old switch case where I understand what's going on. I understand that reflection is a powerful capability for C++, but the template-meta-cryptic-insanity is just too much to invite me back to this version of the language. | | |
| ▲ | SuperV1234 6 minutes ago | parent [-] | | It is "cryptic" and "ugly" to you just because you're not familiar with it. You'd pick the macro-based implementation because you are familiar with it. Seeing this argumentation is so tiresome, because it feels like there is a lack of self-awareness regarding what is "familiar" and what isn't, which is subconsciously translated to "ugly" and "bad". |
| |
| ▲ | randusername 2 hours ago | parent | prev | next [-] | | I was a fool to assume that the same forces shaping the ugliness of C++ syntax would not also be at work in C++ 26. | |
| ▲ | ginko 3 hours ago | parent | prev | next [-] | | Is it? I'm mostly used to (pre-)C++11 and the only unusual operators I see are ^^T (which I presume accesses the metadata info of T) and [:e:] (which I assume somehow casts the enumerator metadata 'e' to a constant value of T). And template for but I assume that's like inline for like in zig. | | |
| ▲ | CamouflagedKiwi 2 hours ago | parent [-] | | requires is also new (not sure exactly when that appeared, it's after the last time I wrote C++ in anger) although I think it's fairly clear what it means. I can only guess at the other two. Not familiar with Zig but AFAICT `inline for` is about instructing the compiler to unroll the loop, whereas `template for` means it can be evaluated at compile time and each loop iteration can have a different type for the iteration variable. It's a bit crazy but necessary for reflection to work usefully in the way the language sets it up. | | |
| |
| ▲ | bluGill 2 hours ago | parent | prev [-] | | You realize c++11 is closer in age to C++98 than C++26? |
|
|
| ▲ | king_geedorah 2 hours ago | parent | prev | next [-] |
| Another win for X macros and for C style in general, though the author didn’t declare it as such. |
| |
| ▲ | SuperV1234 an hour ago | parent [-] | | Author here. It isn't a clear "win" at all, there are tradeoffs to each approach. |
|
|
| ▲ | TZubiri an hour ago | parent | prev [-] |
| "Enum to string" We've come full circle huh? Why do you need this, logging? In that case I would rather reflect the logging statement to pribt any variable name, or hell, just write out the string. If saving for db, maybe store as string, there's more incentive for an enum in the db, if that's a string you might as well. At any rate it doesn't seem a great idea to depend on a variable name, imagine changing a variable name and stuff breaks. |
| |
| ▲ | SuperV1234 4 minutes ago | parent [-] | | Logging, debugging, auto-generation of UIs/editors, etc... This is an extremely common operation and for a good reason. |
|