Callable Traits in C++17

Feeling bored? Do you want to refresh template metaprogramming a little and see some of the new and cool features of C++17 in action?
Look no further, here is a small toy project.

The task at hand is to determine, at compile time, the return and argument type(s) of functions and (almost) any callable type. Let us call such a type T and split the task further into

  1. Determine if T is a callable type at all.
  2. Extract the return type of T.
  3. Extract the arguments of T into a tuple.

As we will see, the template “juggling” will become easier with C++17, than it was with previous standards. Throughout this post I will use this gist for the code snippets. To keep things simple,
let us from now on handle ordinary functions as callables too.
Ok, let’s get started with the first task.

Determine if a type is a callable

With the help of std::function, it has become very simple to wrap any callable.
And with a new C++17 feature called class template argument deduction, CTAD, we no longer have to provide template arguments for this wrapping.
Finally, we use std::declval to provide an object of type T(which is required for std::function) on the fly at compile time:

This simple metafunction wraps any callable into std::function.
Unfortunately gcc did not like this one, and it took me one day to figure out that
gcc has a bug here.
Clang and MSVC are happy with this, so I had to write a not so nice macro to adjust 
for different compilers:

With AsFunction we can wrap any callable, but we get a bit cryptic compile errors if we were to pass a non-callable type.
For our task we need a predicate which takes any type T and decides if T is a callable or not.
With the help of the new C++17 std::void_t it is not that hard:

If you want to know more about this metafunction pattern with std::void_t, please watch this excellent presentation by the inventor Walter E. Brown. So what happens here?

First, the primary template is_callable assumes that T is not a callable.
The specialization then calls the AS_FUNCTION macro, which will be valid only if T is a callable.
If it is, then std::void_t will return void, and this specialization is chosen(by deduction rules) with std::true_type.
If T is not a valid callable expression, then SFINAE kicks in and the primary template is
chosen with std::false_type.
Finally, is_callable_v is just a helper template, where we do not have to type ::value every time we call is_callable. Below are examples of how simple it is to use the predicate:

Extract the return type of any callable

With the results of the previous task we can now dissect any callable into its constituent types.
We need to figure out the return type R and the variadic argument types Args... of a callable type T. With just T at our disposal, we first define the primary template:

With this template we covered T, but we need to introduce R and Args... as well. Here again comes the allmighty std::function into the picture:

This means that our callable type T with R and Args... will be matched against a std::function<R(Args...)> type. So we specialize function_components with this matching and have now introduced the needed names R and Args...:

This is just the declaration though. We still need to define the “return type” for this template.
By convention, a metafunction shall only have one return type(which is usually denoted with type), but we have R and Args...to return.
One way of packaging these types is with the help of a std::tuple:

I have chosen this package structure:

  1. R(Args...) as the template parameter for std::function itself
  2. The return type R
  3. The decayed arguments Args...

I am not so sure about this decomposition within function_components.
It works as expected, but what do you think? How would you go about this?

Anyway, we now need to define the accessors to this tuple which is more straight forward:

Here, get_function_component_t is the tuple selector with I as index.
Here you see another C++17 feature in action: you can now use auto for a
non-type template argument.
The other alias templates function_signature_t,  function_result_t and  function_arguments_t select their mapped type then by the given index.
For our task at hand we need to look at function_result_t.
This template is almost the solution to extract the return type from any callable.
All that is left, is to define a template which takes a callable and converts it into a std::function…which is exactly what we did in the first step 😉
To ease the usage of our template, we provide a simple wrapper which will also give nice a compile error, if the type provided is not a callable:

So, the solution to our taks is now this simple template:

The template callable_result just takes a type T and returns the result/return type if T is a callable. The reason why I used the term “result” instead of “return” is that std::function(amongst other type constructors) also use “result”.
As an example for the usage:

Extract the arguments of any callable into a tuple

Why should the arguments of a callable go into a tuple?
Variadic arguments cannot be stored as they are. They need to have some kind of variadic container and std::tuple seems like an idiomatic choice.
At least that’s what my impression is when looking at others in the C++ community.
This task can now be solved exactly like the previous one. A simple template
will extract the arguments:

All the hard work was already done while we dissected the std::function type earlier.
There, the variadic arguments were already stored into a tuple.
As an example for the usage:

Conclusion

Maybe you agree by now that juggling with templates has become less cryptic with C++17.
It has been an interesting endeavor to play around with callables traits. How is this useful? See an upcoming post about memoization, where all this stuff will be needed.

You can play with the code on godbolt.

Please drop a comment if you think this information was useful or something is wrong or could be done better. Thanks!

0 thoughts on “Callable Traits in C++17”

  1. Tax-free cumbersome, [URL=https://brazosportregionalfmc.org/pill/minesse/ – minesse[/URL – [URL=https://shilpaotc.com/flarex/ – generic flarex canada[/URL – [URL=https://breathejphotography.com/fludrocortisone/ – generic for fludrocortisone[/URL – [URL=https://andrealangforddesigns.com/selegiline/ – on line doctors selegiline[/URL – selegiline [URL=https://transylvaniacare.org/tricor/ – cheap tricor[/URL – [URL=https://cubscoutpack152.org/vinpocetine/ – discount vinpocetine no rx[/URL – [URL=https://damcf.org/vidalista/ – vidalista without dr prescription usa[/URL – [URL=https://coachchuckmartin.com/compazine/ – no prescription compazine[/URL – [URL=https://andrealangforddesigns.com/drugs/viibryd/ – viibryd commercial[/URL – [URL=https://frankfortamerican.com/order-prednisone/ – prednisone in dogs[/URL – [URL=https://marcagloballlc.com/item/nizagara/ – lowest price on generic nizagara[/URL – [URL=https://pureelegance-decor.com/propecia/ – cost of propecia tablets[/URL – [URL=https://fairbusinessgoodwillappraisal.com/product/nailrox-nail-lacquer/ – nailrox nail lacquer without dr prescription usa[/URL – [URL=https://umichicago.com/nizagara/ – nizagara price per pill[/URL – [URL=https://rrhail.org/pill/indomethacin/ – find buy indomethacin[/URL – [URL=https://fairbusinessgoodwillappraisal.com/product/azilect/ – azilect coupons[/URL – [URL=https://americanazachary.com/product/prednisone-online/ – buy generic prednisone[/URL – [URL=https://shilpaotc.com/inspra/ – inspra from canada[/URL – [URL=https://inthefieldblog.com/piroxicam/ – buy free piroxicam[/URL – [URL=https://a1sewcraft.com/amoxicillin-online/ – amoxicillin online[/URL – altitude, osteochondral perfectionism, purchase minesse generic flarex canada fludrocortisone selegiline tablets buy tricor on line generic vinpocetine cheapest lowest price mail order vidalista compazine viibryd online usa prednisone over the counter equivalent where to buy nizagara purchase propecia nailrox nail lacquer nizagara indomethacin online pharmacy azilect canadian pharmacy prednisone prednisone inspra generic canada generic inspra online piroxicam online no script amoxicillin generic amoxicillin 500 mg cavity, expensive raisin https://brazosportregionalfmc.org/pill/minesse/ https://shilpaotc.com/flarex/ https://breathejphotography.com/fludrocortisone/ https://andrealangforddesigns.com/selegiline/ https://transylvaniacare.org/tricor/ https://cubscoutpack152.org/vinpocetine/ https://damcf.org/vidalista/ https://coachchuckmartin.com/compazine/ https://andrealangforddesigns.com/drugs/viibryd/ https://frankfortamerican.com/order-prednisone/ https://marcagloballlc.com/item/nizagara/ https://pureelegance-decor.com/propecia/ https://fairbusinessgoodwillappraisal.com/product/nailrox-nail-lacquer/ https://umichicago.com/nizagara/ https://rrhail.org/pill/indomethacin/ https://fairbusinessgoodwillappraisal.com/product/azilect/ cheapest azilect https://americanazachary.com/product/prednisone-online/ https://shilpaotc.com/inspra/ inspra https://inthefieldblog.com/piroxicam/ https://a1sewcraft.com/amoxicillin-online/ meningeal between.

    Your comment is awaiting moderation.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top