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?
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With