C++ std::apply made usable

So little C++ so much good!

std::apply is used to Invoke a Callable object with a tuple of arguments.

Somehow that statement left me wanting for more. That is one very corralling definition.

std::apply is a typical example of those numerous standard C++ std lib types begging to be made comfortable and usable.  Not just narrowly usable.  I can (you can, we can) see a bit wider scope for std::apply  use cases.

Certainly, one can try and go ahead and just use it. But.  In its raw form, it requires a lot of typing. That code becomes clunky, unreadable and complex.

So, I made one little wrapper that is really simple but makes std::apply usage, much more palatable.

The API

Philosophy is: you first make specific “applicator” from a specific Callable object. Then you use it, wherever you need it.

Thus summator is a proxy to the services of the summa function. summator  now has the methods encapsulating the required interaction of std::apply and the summa function. Thus it delivers simpler and easier to use interface v.s the naked interaction of std::apply and the Callable it is using.

Please find the suma in the Appendix below.

To each example below, I have added std::apply raw usage, on the line below. So that you can compare and decide what works best for you.

Not a big deal. Shorter but just slightly shorter. Ok, how about using tuples, as primary and only argument type to be passed (by design ) to std::apply. Here is the difference.

At least for me, that’s a big difference in ease of usage.

And then there are types that my API can do, and std::apply can not do.

Initializer list’s, std::apply simply does not let you use. And what about native arrays? Yes, I can do too.

I know std::array is rather nice, and I use it too whenever I can, but in real-life code, native arrays no one can avoid. There is a legacy ocean of them native arrays as arguments.  Instead of writing your own transformations, feel free to use my API.

Stunts?

I do not advise stunts, but only this time.  What about this “funky” situation:

F( a, b,  F(c, d))

Function result used as one of the arguments to the same function.

As long as you understand the purpose of std::apply, I am pretty sure you will find a good use for this little utility.  In that case, just use it. Feel fry to experiment.

The Free Code

It is rather simple and lovingly short. C++17 or 20. I am not building console apps so first my primitive logging to the WIN32 message box.

That logging is not part of it but here it is, for the samping code to be used. Now “the core of the trick”.

summator exhibits few call operator overloads. And just simply passes the argument to the apply call on the callable object given at construction time. In the case of a native array, it first transforms it into the std array.

In my tradition, I am not adding any type traits mumbo jumbo compile-time checks. If you use it as ‘Callable above something that is not, the compiler will simply not let you use it.

Similarly, if you manage and use the fact all return values are constexpr go for it. C++20 certainly opens the door for compile-time computing wider.

I think this utility is amazingly simple and improves the quality and readability of the code using it considerably. Enjoy.

Appendix

The summa` used to explain the API above.

The function we will use as the “callable” specimen to which we will “apply” all kinds of arguments. But crucially of the same type.

Of course, all the args above have to be of the same type. They are being simply added together. Hence that static_assert in there.  That is almost easy to code. I am sure you will manage without my explanation.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.