DLunin
DLunin

Reputation: 1070

Get the type of the return value in C++

Suppose we have a function f which returns a value of some unknown type (let's call it T) and takes a value of the type T as an argument (and possibly has some other arguments). How do I get the return type of f in C++14?

There is a way to do it if we know the know the argument types (via std::result_of). Is it possible if we know all the argument types except T?

Example:

template <class F> // F is functor with   T operator()(T a, T b)
class A {
    // Here I want to do
    // T some_function(T some_arg) { ... }
}

Upvotes: 10

Views: 7857

Answers (2)

T.C.
T.C.

Reputation: 137394

Building on @Piotr S.'s excellent answer, for arbitrary functor types, if you know that there's exactly one operator() overload with the right "pattern", so to speak, then you can do something like this:

// leave undefined
template<class C, class T>
T return_type_helper(T (C::*)(T));

template<class C, class T>
T return_type_helper(T (C::*)(T) const);

// 10 additional combinations of ref- and cv- qualifiers omitted, because I'm lazy

template<typename T>
using functor_return_type = decltype(return_type_helper(&T::operator()));

This activates overload resolution and template argument deduction to determine the right operator().

And then you can combine those two:

template <typename... T>
struct voider { using type = void; };

template <typename... T>
using void_t = typename voider<T...>::type;

template<typename T, typename = void>
struct combined_return_type;

template<typename T>
struct combined_return_type<T, void_t<typename return_type<T>::type>> { 
    using type = typename return_type<T>::type;
};

template<typename T>
struct combined_return_type<T, void_t<functor_return_type<T>>> { 
    using type = functor_return_type<T>; 
};

template <typename T>
using return_type_t = typename combined_return_type<T>::type;

Demo.

Upvotes: 5

Piotr Skotnicki
Piotr Skotnicki

Reputation: 48527

template <typename T>
struct return_type;

template <typename R, typename... Args>
struct return_type<R(Args...)> { using type = R; };

template <typename R, typename... Args>
struct return_type<R(*)(Args...)> { using type = R; };

template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...)> { using type = R; };

template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) &> { using type = R; };

template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) &&> { using type = R; };

template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const> { using type = R; };

template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const&> { using type = R; };

template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const&&> { using type = R; };

template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) volatile> { using type = R; };

template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) volatile&> { using type = R; };

template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) volatile&&> { using type = R; };

template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const volatile> { using type = R; };

template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const volatile&> { using type = R; };

template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const volatile&&> { using type = R; };

template <typename T>
using return_type_t = typename return_type<T>::type;

Test:

#include <type_traits>

struct Functor
{
    int operator()(int i, int j) { return i + j; }
};

template <class F>
struct A
{
    using T = return_type_t<decltype(&F::operator())>;

    T some_function(T some_arg) { return some_arg; }
};

int main()
{
    A<Functor> a;
    static_assert(std::is_same<decltype(a.some_function(1)), int>::value, "!");
}

DEMO

Upvotes: 16

Related Questions