Finding out the return type of a function, lambda or function

前端 未结 2 911
醉梦人生
醉梦人生 2021-01-18 18:26

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

相关标签:
2条回答
  • 2021-01-18 18:52

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

    (Taken from here.)

    0 讨论(0)
  • 2021-01-18 18:53

    Assuming that:

    1. You want only the return type.
    2. You don't know what are/will be the types of arguments (so neither decltype() nor std::result_of<> is an option.
    3. The functor object passed as argument will not have an overloaded or generic 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

    0 讨论(0)
提交回复
热议问题