I'm writing a template function that takes a function object (for now, a lambda) as a parameter, with lambda datatype as a template parameter, and returns the same type the lambda returns. Like this:
template<typename TFunctor, typename TReturn>
TReturn MyFunc(TFunctor &Func, TReturn) //The second arg is just to keep the template spec happy
{
return Func();
}
And the consumption code goes like this:
int n = MyFunc([](){return 17;}, int());
I don't like the ugly way the return datatype is specified. Is there some built-in typedef in the compiler-generated lambda class that would give me its return type? So that MyFunc can go somehow like this:
template<typename TFunctor>
TFunctor::return_type MyFunc(TFunctor &Func)
{ //...
I want it to return the same type that lambda returns without explicitly spelling out that type.
EDIT: for now, all lambdas I'm concerned with are argumentless. Variable capture does the trick just as well.
Since the return type can depend on the arguments given to the functor, you need to specify them somewhere in order to query the return type. Therefore, when speaking of generic functors (not restricting them to (non-generic) lambdas), it's not possible to determine the return type when not knowing the types of the arguments.
C++11 has the keyword decltype
which can be used in conjunction with a trailing return type in order to specify the return type of your function by naming an expression which can depend on the function arguments (here, it depends on what Func
is):
template<typename TFunctor>
auto MyFunc(TFunctor &Func) -> decltype(Func(/* some arguments */))
{ ... }
So if you were to call it for example with no argument (I assume this when looking at your lambda example), simply write:
template<typename TFunctor>
auto MyFunc(TFunctor &Func) -> decltype(Func())
{
return Func();
}
In C++14, you can even completely omit the return type and simply write
template<typename TFunctor>
auto MyFunc(TFunctor &Func)
{
return Func();
}
Note that even in C++03, you don't have to provide another function argument; another template argument is enough:
template<typename TReturn, typename TFunctor>
TReturn MyFunc(TFunctor &Func)
{
return Func();
}
int n = MyFunc<int>(someFunctorReturningAnInt);
@leemes answer is nice but as a bonus you can use since C++17 the built-in std::invoke_result_t
:
#include <type_traits>
#include <iostream>
struct S {
double operator()(char, int&);
float operator()(int) { return 1.0;}
};
int main()
{
// std::invoke_result uses different syntax (no parentheses)
std::invoke_result<S,char,int&>::type b = 3.14;
static_assert(std::is_same<decltype(b), double>::value, "");
}
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