Идея отложенного будущего (достигается только путем вызова std::async с флагом std::launch::deferred) заключается в том, что обратный вызов вызывается только тогда, когда кто-то пытается подождать или вытащить футуристическое значение или исключение будущего. к тому времени обратный вызов не выполняется.
Что произойдет, если я прикреплю продолжение к отложенному будущему с std::future::then? отложенное будущее теряется (then аннулирует будущее), и вместо него возвращается новое будущее.
В таком случае по стандарту что должно произойти? новое будущее - это тоже отложенное будущее? это просто тупик? этот вопрос не рассматривается в последней версии документации.
Однако я больше не могу найти это в более новой версии open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0159r0.html





На мой взгляд, это ошибка в ТС. Или, по крайней мере, недокументированная ловушка.
Вот текст из TS:
template <class F> see below then(F&& func);Requires:
INVOKE(DECAY_COPY (std::forward<F>(func)), std::move(*this)) shall be a valid expression.Effects:
The function creates a shared state that is associated with the returned future object. Additionally,
When the object's shared state is ready, the continuation
INVOKE(DECAY_COPY(std::forward<F>(func)), std::move(*this))is called on an unspecified thread of execution with the call toDECAY_COPY()being evaluated in the thread that called then.Any value returned from the continuation is stored as the result in the shared state of the resulting future. Any exception propagated from the execution of the continuation is stored as the exceptional result in the shared state of the resulting future.
Returns:
When
result_of_t<decay_t<F>(future<R>)>isfuture<R2>, for some type R2, the function returnsfuture<R2>. Otherwise, the function returnsfuture<result_of_t<decay_t<F>(future<R>)>>. [ Note: The rule above is referred to as implicit unwrapping. Without this rule, the return type of then taking a callable returning afuture<R>would have beenfuture<future<R>>. This rule avoids such nested future objects. The type off2below isfuture<int>and notfuture<future<int>>:[ Example:
future<int> f1 = g(); future<int> f2 = f1.then([](future<int> f) { future<int> f3 = h(); return f3; });— end example ]
— end note ]
Postconditions:
valid() == falseon the original future.valid() == trueon the future returned from then. [ Note: In case of implicit unwrapping, the validity of the future returned from thenfunc cannot be established until after the completion of the continuation. If it is not valid, the resulting future becomes ready with an exception of typestd::future_error, with an error condition ofstd::future_errc::broken_promise. — end note ]
Нет особого случая для отложенной будущей задачи. Если эта отложенная будущая задача не готова до вызова .then, у нее нет возможности подготовиться, поэтому нет возможности вызвать испорченную копию func.
Текст для shared_future аналогичен; там, однако, вы все равно можете заставить shared_future подготовиться к работе после вызова .then.
Если это предусмотрено; что .then в неготовом отложенном уникальном будущем приведет к возвращаемому значению future, которое никогда не может быть подготовлено - это должно быть явно указано в TS / стандарте. Если это не предусмотрено, стандартный текст необходимо изменить.
Обратите внимание, что эти изменения не отражены в N4762 проект стандарта, опубликованном в 2018 году.
Я не уверен, как стандарт должен это исправить; семантика .then разумна для shared_future, но не для future, и различие семантики было бы неожиданным.
В более ранней версии проекта спецификации (open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3721.pdf) упоминается: Если у родителя есть политика launch :: deferred, а у продолжения нет указанной политики запуска или планировщика, то родительский элемент заполняется немедленным вызовом .wait (), а политика предшествующего элемента - launch :: deferred.