On 9/6/2015 6:26 PM, Giovanni Piero Deretta wrote:
On Sun, Sep 6, 2015 at 7:22 PM, Agustín K-ballo Bergé
wrote: 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>.
I don't quite see this, nor the opposite. Luckily the proposal is still in flux (and I seriously hope it goes into a TS first).
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'.
I thought the concern was that `then` does a bit too much, it consumes the future which would be problematic for `when_any` returning futures that cannot re-obtain until all input futures are ready.
The problematic scenario is performing wait_any multiple times on the same future set as the attached continuations will continue growing every time.
I have not consider this problematic, each call to `wait_any` will cause one memory allocation and it will only release it once all input futures are done. I have not done any specific experimentation on this topic, I might reach the same conclusions as you once I do. My prior experience with `wait_any` includes dealing with hundreds or thousands of futures, going back and "unwaiting" each of them has not ever been a viable approach for me.
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(); }
No, this ^ introduces a copyable requirement.
return x.then([](auto&&) {}); }
future<T> x = ...;
await when_ready(x); // or when_ready(x).then([] { /* do something */ });
Regards, -- Agustín K-ballo Bergé.- http://talesofcpp.fusionfenix.com