Portable concurrency  0.11.0
Implicit unwrapping

If some function returning type R is going to be executed asyncronyously (via async, packaged_task or as continuation for some future or shared_future object) then future<R> object is created in order to provide access to the result of the function invocation. If function itself returns object of type future<R> or shared_future<R> then running it asyncronyously in a naive implementation will create future to future to result. Such future<future<R>> type is quite inconvenient to use and actually forbidden by the portable_concurrency future and shared_future implementation (same is true for any combination of future templates future<shared_future<R>>, shared_future<future<R>> and shared_future<shared_future<R>>). future<R> is always created instead of future<future<R>> and shared_future<R> instead of future<shared_future<R>> by applying rules specified in "The C++ Extensions for Concurrency" TS as implicit unwrapping.

The future unwrapping works as if there are two function template overloads:

  • template<typename R> future<R> UNWRAP(future<future<R>>&& rhs)
  • template<typename R> shared_future<R> UNWRAP(future<shared_future<R>>&& rhs)

which constructs future/shahred_future object from the shared state referred to by rhs. The object becomes ready when one of the following occurs:

  • Both the rhs and rhs.get() are ready. The value or the exception from rhs.get() is stored in the returned object shared state.
  • rhs is ready but rhs.get() is invalid. The returned object stores an exception of type std::future_error, with an error condition of std::future_errc::broken_promise.
Note
Same logick is extended to be applicable for promise<future<T>> and promise<shared_future<T>>. promise::get member function works as UNWRAP(promise_to_future.NAIVE_GET()).