7

I've recently learned that I cannot:

  1. Take the address of an undefined function
  2. Take the address of a templatized function with a type it would fail to compile for

But I've also recently learned that I can call decltype to get the return type of said function

So an undefined function:

int foo(char, short);

I'd like to know if there's a way that I can match the parameter types to the types in a tuple. This is obviously a meta programming question. What I'm really shooting for is something like decltypeargs in this example:

enable_if_t<is_same_v<tuple<char, short>, decltypeargs<foo>>, int> bar;

Can anyone help me understand how decltypeargs could be crafted?

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288

1 Answers1

3

For non-overloaded functions, pointers to functions, and pointers to member functions, simply doing decltype(function) gives you the type of the function in an unevaluated context, and that type contains all the arguments.

So to get the the argument types as a tuple, all you need are a lot of specializations:

// primary for function objects
template <class T>
struct function_args
: function_args<decltype(&T::operator()>
{ };

// normal function
template <class R, class... Args>
struct function_args<R(Args...)> {
    using type = std::tuple<Args...>;
};

// pointer to non-cv-qualified, non-ref-qualified, non-variadic member function
template <class R, class C, class... Args>
struct function_args<R (C::*)(Args...)>
: function_args<R(Args...)>
{ };

// + a few dozen more in C++14
// + a few dozen more on top of that with noexcept being part of the type system in C++17

With that:

template <class T>
using decltypeargs = typename function_args<T>::type;

This requires you to write decltypeargs<decltype(foo)>.


With C++17, we will have template <auto>, so the above can be:

template <auto F>
using decltypeargs = typename function_args<decltype(F)>::type;

and you'd get the decltypeargs<foo> syntax.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • Wow my mind is blown. I didn't have any idea about the `decltype` thing. I was actually writing an answer about how it couldn't be done. +1 Also, I've never seen an `auto` as a template type specifier. Does that just do perfect forwarding? – Jonathan Mee Jul 19 '16 at 12:54
  • 1
    @JonathanMee http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0127r2.html – Barry Jul 19 '16 at 12:56
  • 2
    Might this be a good time to use `typename` rather than `class`? Since you're not passing classes. They're functionally equivalent but readability is important. – Lightness Races in Orbit Jul 19 '16 at 13:36
  • So after trying to work through this for my clarification I have a couple questions: 1) You say "+ a few dozen more in C++14" that pertains only to methods, right? I think your "normal function" definition does everything I need 2) Only the specializations of `function_args` are ever used. Did you choose to define it this way so you could use the specializations to templatize what was being passed in? – Jonathan Mee Jul 19 '16 at 13:42
  • 1
    @JonathanMee 1) member functions. 2) The specializations let you pull apart the types, to get out the parts that you need. – Barry Jul 19 '16 at 13:50
  • @Barry I've asked enough questions here. I'll accept this once the paint finishes drying on the answer. But I do have one more follow up question, which I've posted separately here: http://stackoverflow.com/q/38463980/2642059 – Jonathan Mee Jul 19 '16 at 16:32