How can I retrieve the return type of a function to use in a template?

1.3k views Asked by At

I have a function somewhere called x that returns a know value and has known parameters:

int x(int y);

I have somewhere else, I want to create a container to contain n invocations of this function. Then I want to execute it that many times.

The problem is, I don't want to rely on it being an int return type. I need to deduce the return type at compile time. Something like:

std::vector<result_of<x(int)>::type> results;

But I don't want to have to specify the parameter values because they're static.

4

There are 4 answers

0
Jarod42 On BEST ANSWER

You can create your own traits, something like:

template <typename F> struct my_result_of;

template <typename F> struct my_result_of<F*> : my_result_of<F> {};

template <typename Ret, typename ... Ts>
struct my_result_of<Ret(Ts...)>
{
    using type = Ret;
};

template <typename F> using my_result_of_t = typename my_result_of<F>::type;

And use it like (assuming no overloads of x):

std::vector<my_result_of_t<decltype(x)>::type> results;
0
skypjack On

I assume you can use up to the most recent standard revision, for you didn't specify it.
Here is a minimal, working example:

#include<vector>
#include<functional>
#include<utility>

template<std::size_t... I, typename F, typename... A>
auto gen(std::index_sequence<I...>, F &&f, A... args) {
    return std::vector<decltype(std::forward<F>(f)(args...))>{
        (I, std::forward<F>(f)(args...))...
    };
}

template<std::size_t N, typename F, typename... A>
auto gen(F &&f, A... args) {
    return gen(std::make_index_sequence<N>{}, std::forward<F>(f), args...);
}

int f(int, char) { return 0; }

int main() {
    auto vec = gen<10>(&f, 0, 'c');
}

Return type of your function is easily deduced by:

decltype(std::forward<F>(f)(args...))

I want to create a container to containĀ nĀ invocations of this function. Then I want to execute it that many times.

To do that, I used an std::index_sequence to create a parameter pack having the right size.
Then the vector itself is initialized as it follows:

(I, std::forward<F>(f)(args...))...

The basic idea is to exploit the comma operator to unpack the parameter pack mentioned above and execute N times the function. The values returned by the invokations of f are used to fill the vector.

Note that args are not perfectly forwarded to f.
It could cause problems in case of moveable objects consumed during the first execution.

4
erenon On

You are close. Assuming T is the template argument of the caller function:

std::vector<decltype(x(std::declval<T>()))> results;
0
cpplearner On

You can abuse std::function::result_type:

int x(int y);
static_assert(std::is_same_v<int,std::function<decltype(x)>::result_type>);

Of course this will only work if x is really a function. If x is an arbitrary function object, then its result type may depend on its argument type, in which case you cannot know its result type without specifying the arguments.