Идея отсроченного будущего (достигается только путем вызова std::async
с std::launch::deferred
флаг) заключается в том, что обратный вызов вызывается только тогда, когда кто-то пытается подождать или извлечь футуристическое значение или исключение из будущего. к тому времени обратный вызов не выполняется.
Что произойдет, если я прикреплю продолжение к отложенному будущему с std::future::then
? отложенное будущее потеряно (then
аннулирует будущее), и вместо него возвращается новое будущее.
В этом случае, согласно стандарту, что должно произойти? новое будущее — это также отложенное будущее? это просто тупик? этот вопрос не рассматривается в последней документации.
Это, на мой взгляд, похоже, ошибка в TS. Или, по крайней мере, недокументированная ловушка.
Вот текст из TS:
template <class F> see below then(F&& func);
Требуется:
INVOKE(DECAY_COPY (std::forward<F>(func)), std::move(*this)) shall be a valid expression.
Последствия:
Функция создает общее состояние, которое связано с возвращенным будущим объектом. Дополнительно,
Когда общее состояние объекта готово, продолжение
INVOKE(DECAY_COPY(std::forward<F>(func)), std::move(*this))
вызывается в неопределенном потоке выполнения с вызовомDECAY_COPY()
оценивается в потоке, который вызвал тогда.Любое значение, возвращаемое из продолжения, сохраняется как результат в общем состоянии результирующего будущего. Любое исключение, переданное из выполнения продолжения, сохраняется как исключительный результат в общем состоянии результирующего будущего.
Возвращает:
когда
[ Пример:result_of_t<decay_t<F>(future<R>)>
являетсяfuture<R2>
для некоторого типа R2 функция возвращаетfuture<R2>
, В противном случае функция возвращаетfuture<result_of_t<decay_t<F>(future<R>)>>
, [Примечание: вышеприведенное правило называется неявной разверткой. Без этого правила тип возврата затем принимает вызываемый, возвращающийfuture<R>
был быfuture<future<R>>
, Это правило избегает таких вложенных будущих объектов. Типf2
нижеfuture<int>
и неfuture<future<int>>
:future<int> f1 = g(); future<int> f2 = f1.then([](future<int> f) { future<int> f3 = h(); return f3; });
— конец примера]
— конец примечания]
Постусловия:
valid() == false
на оригинальное будущее.valid() == true
на будущее вернулся с тех пор. [Примечание: в случае неявного развертывания действительность будущего, возвращенного из thenfunc, не может быть установлена до завершения продолжения. Если он недействителен, получающееся будущее становится готовым, за исключением типаstd::future_error
с условием ошибкиstd::future_errc::broken_promise
, — конец примечания]
Для отложенного будущего задания особого случая не существует. Если это отложенное будущее задание не готово перед вызовом .then
нет никакого способа, чтобы это было готово, таким образом, нет никакого способа для разложившейся копии func
быть призванным.
Текст для shared_future
похож; там вы все равно можете вызвать shared_future
быть готовым после звонка .then
тем не мение.
Если это предназначено; тот .then
в неготовом отложенном уникальном будущем приведет к возвращаемому значению future
это никогда не может быть подготовлено — это должно быть явно указано в стандарте TS /. Если это не предназначено, стандартный текст должен быть изменен.
Обратите внимание, что эти изменения не отображаются в Проект стандарта N4762 опубликовано в 2018 году.
Я не уверен, как стандарт должен это исправить; .then
семантика разумна для shared_future
но не для future
и отличающаяся семантика была бы удивительной.
Других решений пока нет …