Reputation: 2249
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.
Upvotes: 9
Views: 1429
Reputation: 15813
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.
Upvotes: 3
Reputation: 50540
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.
Upvotes: 2
Reputation: 217085
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;
Upvotes: 6
Reputation: 19118
You are close. Assuming T
is the template argument of the caller function:
std::vector<decltype(x(std::declval<T>()))> results;
Upvotes: 5