Given a lambda, is it possible to figure out it's parameter type and return type? If yes, how?
Basically, I want lambda_traits
which can be used in following ways:
auto lambda = [](int i) { return long(i*10); };
lambda_traits<decltype(lambda)>::param_type i; //i should be int
lambda_traits<decltype(lambda)>::return_type l; //l should be long
The motivation behind is that I want to use lambda_traits
in a function template which accepts a lambda as argument, and I need to know it's parameter type and return type inside the function:
template<typename TLambda>
void f(TLambda lambda)
{
typedef typename lambda_traits<TLambda>::param_type P;
typedef typename lambda_traits<TLambda>::return_type R;
std::function<R(P)> fun = lambda; //I want to do this!
//...
}
For the time being, we can assume that the lambda takes exactly one argument.
Initially, I tried to work with std::function
as:
template<typename T>
A<T> f(std::function<bool(T)> fun)
{
return A<T>(fun);
}
f([](int){return true;}); //error
But it obviously would give error. So I changed it to TLambda
version of the function template and want to construct the std::function
object inside the function (as shown above).
Though I'm not sure this is strictly standard conforming, ideone compiled the following code:
However, this provides only the function type, so the result and parameter types have to be extracted from it. If you can use
boost::function_traits
,result_type
andarg1_type
will meet the purpose. Since ideone seems not to provide boost in C++11 mode, I couldn't post the actual code, sorry.The answer provided by @KennyTMs works great, however if a lambda has no parameters, using the index arg<0> does not compile. If anyone else was having this problem, I have a simple solution (simpler than using SFINAE related solutions, that is).
Just add void to the end of the tuple in the arg struct after the variadic argument types. i.e.
since the arity isn't dependent on the actual number of template parameters, the actual won't be incorrect, and if it's 0 then at least arg<0> will still exist and you can do with it what you will. If you already plan to not exceed the index
arg<arity-1>
then it shouldn't interfere with your current implementation.Funny, I've just written a
function_traits
implementation based on Specializing a template on a lambda in C++0x which can give the parameter types. The trick, as described in the answer in that question, is to use thedecltype
of the lambda'soperator()
.Note that this solution does not work for generic lambda like
[](auto x) {}
.The specialization method shown in @KennyTMs answer can be extended to cover all cases, including variadic and mutable lambdas:
Demo.
Note that the arity is not adjusted for variadic
operator()
s. Instead one can also consideris_variadic
.