2

Given any functor, I'd like to pull out the type of the first parameter that it takes. It can be assumed that the functor takes only one parameter. I can do this with functions, but am looking for a solution for functors.

#include <iostream>
#include <utility>

template <typename T>
struct test;

template <typename R, typename P>
struct test<R(*)(P)>
{
    typedef R R_t;
    typedef P P_t;
};

void fn(int value)
{
    std::cout << "function called " << value << std::endl;
}

int main()
{
    using namespace std;
    cout << typeid(test<decltype(&fn)>::R_t).name() << endl;
    cout << typeid(test<decltype(&fn)>::P_t).name() << endl;
}
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Adrian
  • 10,246
  • 4
  • 44
  • 110

2 Answers2

1

The solution

Given:

template <typename T>
struct member_function_traits;

template <typename C, typename R, typename... Args>
struct member_function_traits<R(C::*)(Args...)> {
    using return_type = R;

    template <std::size_t i>
    struct param {
        typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
    };
};

you can do:

template<typename Functor>
struct functor_traits {
    using return_type = typename member_function_traits<decltype(&Functor::operator())>::return_type;

    template<std::size_t i>
    using param = typename member_function_traits<decltype(&Functor::operator())>::template param<i>;
};

Example

So for example, having:

struct functor {
    void operator()(int) {}
};

the following program:

std::cout << std::is_same<functor_traits<functor>::return_type, void>::value << std::endl;
std::cout << std::is_same<functor_traits<functor>::param<0>::type, int>::value << std::endl;

would print:

1
1

Live demo

Shoe
  • 74,840
  • 36
  • 166
  • 272
1

If u just want the first parameter type, then you can use partial specialization, with variadic template to separate first parameter and rest parameters.

My approach is same as Jeffery, but doesn't use tuple.

template<typename T>
struct member_fn_traits;

template<typename C, typename R, typename First, typename... Rest>
struct member_fn_traits<R (C::*)(First, Rest...)>
{
    using first_type = First;
};

template<typename Functor>
struct fn_traits
{
     using first_type = typename member_fn_traits<decltype(&Functor::operator())>::first_type;
};

struct functor 
{
    void operator()(int*, int) {}
};


auto main()
{
    auto first_var = fn_traits<functor>::first_type{};
}
vito
  • 473
  • 1
  • 7
  • 17