На мой взгляд, это ошибка в ТС. Или, по крайней мере, незадокументированная ловушка.
Вот текст из ТС:
2.3 [futures.unique_future]/6-10
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
, и другая семантика была бы неожиданной.
person
Yakk - Adam Nevraumont
schedule
29.08.2018