Fun with C++26 reflection: Keyword Arguments
The blog post explores implementing order-independent keyword arguments in C++26 using reflection, discussing limitations of existing methods, proposing new techniques, and highlighting challenges in parsing lambda captures for implementation.
Read original articleThe blog post discusses the implementation of order-independent keyword arguments in C++ using the proposed reflection features of C++26. The author shares insights gained from experimenting with these features, highlighting the potential of reflection to enhance C++'s argument handling capabilities. The post outlines various methods to achieve keyword argument-like syntax, starting with designated initializers introduced in C++20, which allow for a form of keyword arguments but come with limitations such as requiring extra type definitions and maintaining order sensitivity. The author then presents a more flexible approach using helper objects and operator overloading to create a syntax resembling traditional keyword arguments. The discussion progresses to a reflective approach, where keyword arguments can be collected into a named tuple, allowing for optional and order-independent arguments. The author also introduces a macro to simplify the creation of keyword argument tuples and explores the use of lambda closures to manage captures as keyword arguments. The post concludes with a discussion on parsing lambda capture lists to facilitate the implementation of keyword arguments, emphasizing the complexity of parsing C++ syntax correctly. Overall, the post serves as a technical exploration of enhancing C++ function calls through innovative use of reflection and syntactic sugar.
- The blog explores implementing keyword arguments in C++26 using reflection.
- It discusses limitations of existing methods like designated initializers and proposes new techniques.
- The author introduces helper objects and macros to simplify keyword argument syntax.
- Reflection allows for order-independent and optional keyword arguments.
- The post highlights challenges in parsing lambda captures for keyword argument implementation.
Related
Reflection for C++26
The P2996R4 document proposes a reduced set of static reflection features in C++26, using constant expressions, a reflection operator, metafunctions, and splicers. Implementation progress is ongoing by Lock3 and EDG.
Quote-unquote "macros"
The blog post examines macros in the Janet programming language, highlighting their advantages over traditional memoization, particularly in compile-time storage allocation and the significance of quoting and unquoting in macro development.
Code Generation in Rust vs. C++26
The blog post compares code generation in Rust and upcoming C++26, focusing on reflection features. It highlights Rust's procedural macros and proposes a C++ solution using annotations for similar capabilities.
Reflection in C++26: Metafunctions for Enums and Classes
C++26 introduces compile-time reflection for enumerations and classes, enabling introspection and manipulation through metafunctions. The blog showcases code examples and discusses future explorations of these features.
A C++ Mixin System
A proposed C++ mixin system aims to improve code organization by using Rust-like error handling, data constructors, and CRTP, though the author is uncertain about its practical implementation.
Can you imagine an engineer that is adamant on using his mystifying bespoke tool instead of just using a ruler. "But what if I have to measure it in the 4th dimension!?".
I was expecting something simple but good Lord, its kwargs. Not some magical asynchronous runtime.
inb4 there are still corner cases so you can't just say "users don't have to know the implementation details so only one person has to suffer". I bet money this abstraction is leaky.
Why can't you just do this at the language level like any sane person?
FooArgs fooArgs;
fooArgs.y = 4;
foo(fooArgs); // Didn't set .x so it has default value
Three lines instead of one seems like a lot of overhead, but in practice you would only bother for a function that takes loads of arguments so the extra overhead is really much smaller.----
Smaller points:
Are the fields in FooArgs really initialised if they're not explicitly set? I can believe they are, after all it's brace initialisation. But IMHO that code isn't super obvious. I'd be more comfortable if they had default member initialisers, i.e., "int x = 0; int y = 0;" in FooArgs. In my version above, you really do need these (unless you remember to brace initialise).
It took me a while to see why they bothered to have a string template parameter for TypedArg in the first usage. It prevents mixing up two arguments: if TypedArg didn't have that, then you could call foo(y=3, x=2) and it would compile but have the effect that the parameter x would be 3 and y would be 2.
foo($(bar)=10, $(baz)="hello");
In fact you could 10 years ago when I implemented it[1]; in fact it allows significantly more than just named arguments (named tuples!), but please, consider it as some sort of art and not really something that should be anywhere close to production.[1] https://github.com/gpderetta/libtask/blob/a5e6e16ddc4e00d9f7...
foo({.x=2, .y=2})
I remember using this syntax in C in my 2017 project. This is very clear to call methods like that, I used it with minor #defines, i found the inspiration in the book "21st century C."But some of these new features… I feel like they're a bit desperate attempts at fitting in with the kids.
Not to start a language war, but I don't see how any attempt at stapling modern features onto C++ make it a good choice in 2025. There are at least two viable plug in replacements, that have good interop.
Like I said, I've coded C++ for 30 years (along with other languages, sure), so I'm not a fad follower. I don't say it lightly, but I do say that coding C++ in 2025 means creating technical debt. And these features won't change that.
https://prabhuullagaddi.substack.com/p/simulation-of-keyword...
Things like serializers and MVC event bindings come to mind.
Foo(10, 20)
In your code gets rendered in the IDE as
Foo(X=10, Y=20)
Which solves a subset of the problems named parameters solves, namely the readability of the code.
And, being conpile-time, it ain't gonna be pretty. The new operator is nice. They found something that'll work compatibly with existing code. This is not easy stuff.
Related
Reflection for C++26
The P2996R4 document proposes a reduced set of static reflection features in C++26, using constant expressions, a reflection operator, metafunctions, and splicers. Implementation progress is ongoing by Lock3 and EDG.
Quote-unquote "macros"
The blog post examines macros in the Janet programming language, highlighting their advantages over traditional memoization, particularly in compile-time storage allocation and the significance of quoting and unquoting in macro development.
Code Generation in Rust vs. C++26
The blog post compares code generation in Rust and upcoming C++26, focusing on reflection features. It highlights Rust's procedural macros and proposes a C++ solution using annotations for similar capabilities.
Reflection in C++26: Metafunctions for Enums and Classes
C++26 introduces compile-time reflection for enumerations and classes, enabling introspection and manipulation through metafunctions. The blog showcases code examples and discusses future explorations of these features.
A C++ Mixin System
A proposed C++ mixin system aims to improve code organization by using Rust-like error handling, data constructors, and CRTP, though the author is uncertain about its practical implementation.