找出函数,lambda或函数的返回类型

时间:2015-01-07 15:04:16

标签: c++ c++11

这似乎是this question中lambda的情况所解决的。但那个是2011年的答案,我正在寻找一个普遍的案例:lambdas,常规函数和函子。并且,如果可能的话,通过最现代的c ++语言添加。 (注意:g++ -std=c++1y test.cpp)。

所以,给定一个函数(或一个lambda),我试图找出它的返回类型是什么。例如,声明一个变量(简化的情况)。

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);
}

感谢。

2 个答案:

答案 0 :(得分:6)

std::result_of<h(int)>::type a;

(取自here。)

答案 1 :(得分:5)

假设:

  1. 您只想要返回类型。
  2. 您不知道参数类型是什么/将是什么(因此decltype()std::result_of<>都不是一个选项。
  3. 作为参数传递的仿函数对象不会有重载或通用operator()
  4. 然后你可以使用下面的特性来推断任何仿函数对象的返回类型:

    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;
    

    试验:

    #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