Zizheng Tai
Zizheng Tai

Reputation: 6616

Extract return and argument types from a conversion operator to function pointer

Is it possible to write a template to extract the return type and argument types of the function pointer type to which a class is convertible to, knowing only the class itself? Example:

struct Foo {
    using FnPtr = int (*)(char, double);

    operator FnPtr() const { ... }
};

// Can I extract the return type (int) and argument types (char and double),
// knowing only `Foo` as an opaque type?

Upvotes: 2

Views: 174

Answers (2)

TartanLlama
TartanLlama

Reputation: 65620

If Foo doesn't have any other conversion operators and doesn't define an indirection operator, then you can rely on the fact that *a_foo will give a reference to a function of the desired type. From that, you just need to extract the return and arguments.

func_ref_traits here will do the extraction:

template <typename Func>
struct func_ref_traits;

template <typename Ret, typename... Args>
struct func_ref_traits<Ret(&)(Args...)> {
    using ret = Ret;
    using args = std::tuple<Args...>;
};

Then conv_func_traits will work out the function type from the given type:

template <typename T>
using conv_func_traits = func_ref_traits<decltype(*std::declval<T>())>;

You would use this like so:

conv_func_traits<Foo>::args //std::tuple<char,double>
conv_func_traits<Foo>::ret //int

Upvotes: 6

MadScientist
MadScientist

Reputation: 3460

Here you go:

#include <type_traits>

template <typename...> struct typelist;

template <typename> struct Extract;

template <typename R, typename ...Args>
struct Extract<R(*)(Args...)>
{
  using Result = R;
  using Arguments = typelist<Args...>;
};



template <typename T>
using Return_Type = typename Extract<typename T::FnPtr>::Result;

template <typename T>
using Arguments = typename Extract<typename T::FnPtr>::Arguments;




struct Foo
{
  using FnPtr = int (*)(char, double);
};


int main()
{
  static_assert(std::is_same<Return_Type<Foo>, int>::value, ":(");
  static_assert(std::is_same<Arguments<Foo>, typelist<char, double>>::value, ":(");
}

I used a typelist to represent the arguments, you could use std::tuple if you like that better. Additionally, you may need more specializations of Extract to cover different kinds of callable things.

Upvotes: 3

Related Questions