Ответ 1
Это, на мой взгляд, кажется ошибкой в TS. Или, по крайней мере, недокументированная ловушка.
Вот текст из TS:
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
, и различающиеся семантика будет удивительно.