On Sun, Sep 6, 2015 at 7:22 PM, Agustín K-ballo Bergé
On 9/6/2015 1:35 PM, Peter Dimov wrote:
Hartmut Kaiser wrote:
template <typename Future...> requires(is_future<Future>)... future
> when_all(Future &&... f) { (await f)...; return make_tuple(std::forward<Future>(f)...); } I've always found when_any much more interesting than when_all. Is it as trivial to implement with await as when_all?
The await proposal already deals with heterogeneous futures (awaitable types). It comes with traits and customization points on top of which it is built. Using `await_suspend` one can attach a callback to an awaitable object that fires when the future becomes ready (without consuming it). An heterogeneous `when_all` would be built on top of `await_suspend`, plain `await` is optimal when one just want the semantic of `when_all`. Similarly, an heterogeneous `when_any` would use `await_suspend` to attach a callback to all awaitable objects, and the first callback to run would make the resulting future ready (potentially but not necessarily canceling all other callbacks).
In the last coroutine proposal (is it N4499). It seems that await_suspend(h) is guaranteed to work only if 'h' is of type coroutine_handle<P>. Also, at least from the example implementation in N4286, await_suspend is not really more powerful than 'then'. In fact the previous when_all implementation and the when_any you've described can be implemented on top of 'then'. The problematic scenario is performing wait_any multiple times on the same future set as the attached continuations will continue growing every time. BTW, it is sort of possible (but quite inefficient) to attach a continuation to an unique future without consuming it: template<class T> future<void> when_ready(std::future<T>& x) { auto shared_x = x.share(); x = shared_x.then([](auto&&x) { return x.get(); } return x.then([](auto&&) {}); } future<T> x = ...; await when_ready(x); // or when_ready(x).then([] { /* do something */ }); -- gpd