This seems to be solved for the case of lambdas in this question. But that one is a 2011 answer and I'm looking for a general case: lambdas, regular functions, and functors. And, if possible, by means of the most modern c++ language additions. (Note: g++ -std=c++1y test.cpp
).
So, given a function (or a lambda), I'm trying to find out what its return type is. For instance, to declare a variable (simplified case).
using namespace std;
template<typename F>
void test (F h) {
// any of the following should be equivalent to int a; int b; int c;
decltype(h) a; // <<<<< wrong
result_of(h) b; // <<<<<< wrong
result_of<decltype(h)> c; // <<<<<< wrong
}
int a_function (int i) {
return 2*i;
}
int main () {
test (a_function);
}
Thanks.
The return type for a lambda is specified using a C++ feature named 'trailing return type'. This specification is optional. Without the trailing return type, the return type of the underlying function is effectively 'auto', and it is deduced from the type of the expressions in the body's return statements.
Lambda functions are syntactically restricted to return a single expression. You can use them as an anonymous function inside other functions. The lambda functions do not need a return statement, they always return a single expression.
A return statement is not an expression in a lambda expression. We must enclose statements in braces ({}). However, we do not have to enclose a void method invocation in braces. The return type of a method in which lambda expression used in a return statement must be a functional interface.
Lambda expression in C++ Generally return-type in lambda expression are evaluated by compiler itself and we don't need to specify that explicitly and -> return-type part can be ignored but in some complex case as in conditional statement, compiler can't make out the return type and we need to specify that.
Assuming that:
decltype()
nor std::result_of<>
is an option.operator()
.then you can use the below trait that infers the return type of any functor object:
template <typename F>
struct return_type_impl;
template <typename R, typename... Args>
struct return_type_impl<R(Args...)> { using type = R; };
template <typename R, typename... Args>
struct return_type_impl<R(Args..., ...)> { using type = R; };
template <typename R, typename... Args>
struct return_type_impl<R(*)(Args...)> { using type = R; };
template <typename R, typename... Args>
struct return_type_impl<R(*)(Args..., ...)> { using type = R; };
template <typename R, typename... Args>
struct return_type_impl<R(&)(Args...)> { using type = R; };
template <typename R, typename... Args>
struct return_type_impl<R(&)(Args..., ...)> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...)> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...)> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) &> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) &> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) &&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) &&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) const> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) const> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) const&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) const&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) const&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) const&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) volatile> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) volatile> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) volatile&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) volatile&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) volatile&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) volatile&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) const volatile> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) const volatile> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) const volatile&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) const volatile&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) const volatile&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) const volatile&&> { using type = R; };
template <typename T, typename = void>
struct return_type
: return_type_impl<T> {};
template <typename T>
struct return_type<T, decltype(void(&T::operator()))>
: return_type_impl<decltype(&T::operator())> {};
template <typename T>
using return_type_t = typename return_type<T>::type;
Tests:
#include <type_traits>
template <typename F>
void test(F h)
{
static_assert(std::is_same<return_type_t<F>, int>{}, "!");
return_type_t<F> i = 1;
}
int function(int i) { return 2*i; }
int c_varargs_function(...) { return 1; }
struct A
{
int mem_function(double, float) { return 1; }
};
int main()
{
// Function
test(function);
// C-style variadic function
test(c_varargs_function);
// Non-generic lambda
test([](int i) { return 2*i; });
// Member function
test(&A::mem_function);
}
DEMO
std::result_of<h(int)>::type a;
(Taken from here.)
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