5

I have two functions f and g. f calculates it's return value asynchronously and returns a future. Now, based on several return values of f, I want to call g, but I want to make sure that the computations of the values of f happen in parallel.

Consider the following code:

template <typename T>
std::future<T> f(T& t);

template <typename... T>
void g(T&&... t)

template <typename... T>
void call_wrapper(T&&... t) {
  auto f1 = f(t1); // How do I set the values of f1... fn
  auto f2 = f(t2);
  ...
  g(f1.get(), f2.get()....); // How do I call g
}

How can I unpack the types from the variadic template T of the call_wrapper function?

ssb
  • 7,422
  • 10
  • 36
  • 61

2 Answers2

5

[Edit2: I guess i misunderstood the question, i forgot subzero wanted to return std::futures and simply thought that the only problem was the parameter pack syntax. Hopefully, using an helper function as in my first edit should work though]

You can simply do:

template <typename... T>
void call_wrapper(T&&... t) {
  g(f(std::forward<T>(t)).get()...);
}

Unless i misunderstood what you want to do.

Edit1: if you want to do something else, you can divide the function in two calls, like this:

template<typename... T>
void helper(T&&... t) {
  // ...
  g(std::forward<T>(t).get()...);
}

template <typename... T>
void call_wrapper(T&&... t) {
  helper(f(std::forward<T>(t))...);
}
Caninonos
  • 1,214
  • 7
  • 12
  • That should work, as in it will compute the right value, but the computations of `f` won't happen in parallel. The first argument will be calculated, then the second and so on. – ssb Aug 02 '15 at 18:09
  • that could work... making the `future`s in one function and calling the `get()`s in another – ssb Aug 02 '15 at 18:13
  • Ah, i forgot about "in parallel", sorry, maybe the second form would work then, but i'm not sure, i'll edit to state that i misunderstood a part of your question. – Caninonos Aug 02 '15 at 18:14
  • Leveraging the fact that all arguments are evaluated before the call. Neat ! – Quentin Aug 02 '15 at 18:24
  • Your example doesn't compile. `t` isn't expanded in `helper`. – David G Aug 02 '15 at 18:40
3

Here's a quick solution storing the std::futures in a std::tuple :

template <class T, std::size_t... Idx>
void callG(T &tuple, std::index_sequence<Idx...>) {
    g(std::get<Idx>(tuple).get()...);
}

template <typename... T>
void call_wrapper(T&&... t) {
    auto results = std::make_tuple(f(std::forward<T>(t))...);
    callG(results, std::index_sequence_for<T...>{});
}

Live on Coliru

T.C.
  • 133,968
  • 17
  • 288
  • 421
Quentin
  • 62,093
  • 7
  • 131
  • 191