Wow. That is... certainly some syntax. It reminds me of Perl.
This syntax is pretty weird even by C++ standards, and it's certainly the worst way to do reflection I've personally seen. But I guess it's good that C++ is finally getting some kind of reflection. Only a few decades late to the party but hey they got there in the end.
Really as C++ grows and evolves, I feel more and more that I'd rather use plain C than wrangle with all of the bizzarro choices C++ has made. C++ is more and more often just the wrong choice of language for anything I want to do. If I need compile-time reflection, I'll use a C# program to generate C code.
As for syntax, note that as the author says:
> I do not have access yet to a true C++26 compiler. When C++26 arrive, we will have features such as ‘template for’ which are like ‘for’ loops, but for template metaprogramming. Meanwhile, I use a somewhat obscure ‘expand’ syntax.
In particular, regarding the most cryptic line:
[:expand(nonstatic_data_members_of(^^T, ctx)):] >> [&]<auto member>{
In fact, at least from what I know, `expand()` and this fancy use of `>>` aren't actually part of the standard (the standard proposal uses them as an temporary example in case other features didn't get in). The equivalent (I think) line with the C++26 approved features would be a bit more friendly:
template for (constexpr auto member : nonstatic_data_members_of(^^T, ctx)) {
So while it's still not the prettiest thing in the world and knowing C++, it surely will produce some eldritch metaprogramming abominations, the author's examples made it look slightly uglier than it actually is.
The comparison with Perl is apt, to my mind. Both Perl and C++ were early to their space, experimenting with concepts that were weird at the time, trying many approaches we now find ugly, and serving as examples of both successes and failures for the much better languages that came after them. The difference is that Perl5 stopped evolving some time ago, while C++ continues the same tendency unabashed.
(Scala is another example of such a language.)
Are you suggesting that reflection is a new fancy thing and c++ is paving the way?
No; OOP, metaprogramming, exceptions, etc were sort of new in early 1990s in an efficiently compiled language, so C++ was paving its part of way, in an awkward manner, trying hard to make abstractions zero-cost. (I mean mainstream; Common Lisp had all these for a long time, and in an elegant way, but the cost is non-zero.)
Equally, Perl explicitly tried a number of syntactic ways to do something; some stuck as good ideas, some were demonstrated to be... less good. I think it was important to explore and show that a particular approach has serious downsides in practice, but it's not necessary to stick to in once better alternatives are available.
> If I need compile-time reflection, I'll use a C# program to generate C code.
This isn't reflection though, it's just textual code generation. In a way, it has the same problem's Rust's macros have (and indeed I'd love to have this kind of reflection in Rust). As an example, if you're implementing some kind of automated serialization, given an input struct with several fields, how can you even just find out its size? Or at what offset each field lives? Or if the field can be naively memcpy'd? You can hardcode the values if you do lots of assumptions and restrictions, or you can re-implement the logic the compilers already also do - but IMO it does feel the cleanest to just ask the compiler at compile time, which is exactly what C++ reflection proposal does.
> compile-time reflection
> use a C# program to generate C code
These seem at odds.
you call the C# program that generates the code as part of your build system
I get it. That's code generation. But it's not compile time reflection.