Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting function object (functor) and lambda traits

How can I detect the return type and parameter types of nullary and unary function pointers, std::function objects, and functors (including lambdas)?

Boost's function_traits and functional traits don't quite get me there out of the box, but I'm open to supplementing or replacing them.

I could do something like this:

namespace nsDetail
{
    class Dummy { Dummy(); };
}

template<class Fn> struct FnTraits;

template<class R>
struct FnTraits<R(*)()>
{
    typedef nsDetail::Dummy ParamType;
    typedef R               ReturnType;
    typedef R Signature();
};

template<class R, class P>
struct FnTraits<R(*)(P)>
{
    typedef P ParamType;
    typedef R ReturnType;
    typedef R Signature( P );
};

template<class R>
struct FnTraits< std::function<R()> >
{
    typedef nsDetail::Dummy ParamType;
    typedef R               ReturnType;
    typedef R Signature();
};

template<class R, class P>
struct FnTraits< std::function<R(P)> >
{
    typedef P ParamType;
    typedef R ReturnType;
    typedef R Signature( P );
};

But how should I specialize for functors/lambdas?

Update: Perhaps something like in this answer to a different question, but translated from overloading to specialization?

like image 382
metal Avatar asked Jun 01 '11 13:06

metal


2 Answers

It's not possible in the general case for functors, i.e. class types using operator(). This includes lambda objects, too. Consider a case where operator() is overloaded:

struct functor {
    double
    operator()(double) const;

    int
    operator()(int) const;
};

typedef function_traits<functor>::result_type result_type;

What should result_type be?

Note that, as a workaround, some protocols (e.g. boost::apply_visitor from Boost.Variant) require that a result_type be present in the class, with the assumption that all overloads, while accepting different types, all return a type compatible with this result_type.

And of course given some types T0 ... Tn, std::result_of<functor(T0, ..., Tn)>::type gives the return type associated to the parameter types.


In the case where exactly one overload of operator() is present[1], you can take the operator() member and inspect that.

struct not_overloaded {
    double
    operator()(double) const;
};

template<typename T>
struct functor_traits {
    typedef decltype(&T::operator()) type;
};

functor_traits<not_overloaded>::type has type double (not_overloaded::*)(double) const here, and with just a bit of effort you can extract from this what you want. (e.g. a specialization of the form Ret (T::*)(Args...) const will match that type.)

[1]: but a functor can provide functionality by implicitly converting to a function pointer/reference, too, so you could miss that

like image 75
Luc Danton Avatar answered Oct 24 '22 00:10

Luc Danton


What's wrong with std::result_of?

http://en.wikipedia.org/wiki/C%2B%2B0x#Uniform_method_for_computing_the_return_type_of_function_objects

like image 20
sehe Avatar answered Oct 24 '22 01:10

sehe