In this post, I have improved the dbj::print()
lambda from the part one.
Allow me to analyze it for you in a bit of a detail. First what you like most, the code.
(Alternatively if you feel brave and kind of a clear headed, feel free to snub this beginners text and jump straight to Part 3 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
inline auto print = []( // there must be one auto && first_param, // there can be // zero or more auto && ... params ) { win::con::out(first_param); // if here are more params if constexpr (sizeof...(params) > 0) { // recurse with the rest print(params...); } return print; }; |
This version has to receive minimum one argument. Second is param pack. Which might be non existent. This is valid call:
dbj::print(1) ; // one argument
This is also valid call
dbj::print(1, true ) ; // two arguments
So, it must be one or more arguments. And that makes this version so simple but workable. You simply output the first argument, that has to exist. And then, if there are more, you recursively call with the rest of arguments.
win::con::out()
is part of my windows console library. You can replace that call with your favorite set of overloads to process whatever you want to print, or simply just use std::cout
if you fancy copy/paste into your code.
1 2 3 4 5 6 7 8 9 10 11 |
namespace dbj { inline auto print = [](auto && ... param) { if constexpr (sizeof...(param) > 0) { // C++17 fold ( std::cout << ... << param); } return print; }; } |
Now this is even simpler. Zero or more arguments is allowed. We also use C++17 fold feature, thus no recursion.
But, wait. What is that? return print
, on the bottom?
Here we return the lambda from the same lambda in itself. Yes. That is possible. Compiles and works. This gives me the CallStream pattern that I have discovered (using JavaScript) and was writing about sometimes ago. But this time it is in a modern C++:
1 2 3 4 5 6 |
/* meta call aka "call stream" in modern C++ */ dbj::print("dbj")("print")("call")("stream") ; /* */ |
This lambda by the way replaces the whole article full of non trivial C++98 code I had to write to do C++ implementation of the CallStream.
This also shows the power of the auto
keyword. Without it it will be (almost) impossible to declare the type of the lambda in use or to declare and code fiddly template declarations for a generic template function variant of this code.
Instead we have extremely simple and extremely powerful idiom in extremely small amount of modern C++ code.
And the last interesting detail? Why is all of this in an non anonymous namespace? Well this is not strictly related to CallStream in C++ but is yet another rather interesting fact of modern C++. About which I shall write next time.
That is a lot of extremes for one post :)