21

延迟未来(仅通过std::async使用std::launch::deferred标志调用实现)背后的想法是,只有当有人试图等待或提取未来的未来值或异常时才会调用回调。到那时回调不会执行。

如果我将 continuation 附加到 deferred future 会发生什么std::future::then?延迟的未来会丢失(then使未来无效),而是返回一个新的未来。

这种情况下,按照标准,应该怎么办?新的未来也是延迟的未来吗?它会只是僵局吗?最新文档中没有解决这个问题。

4

1 回答 1

2

在我看来,这似乎是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>)>>。[ 注意:上述规则称为隐式展开。如果没有此规则,则 then 采用可调用返回 a 的返回类型future<R>将是future<future<R>>。此规则避免了此类嵌套的未来对象。下面的类型f2future<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返回的future的有效性直到继续完成之后才能确定。如果它无效,则生成的 future 将准备好,但类型为异常,std::future_error错误条件为std::future_errc::broken_promise。——尾注]

延迟的未来任务没有特殊情况。如果该延迟的未来任务在调用 之前尚未准备好.then,则无法使其准备就绪,因此func无法调用 的衰减副本。

的文本shared_future是相似的;在那里,您仍然shared_future可以在调用后使 准备就绪.then

如果这是有意的;在.then未准备好的延迟唯一未来上,将导致 a 的返回值future永远无法准备好——这在 TS/标准中应该是明确的。如果不打算这样做,则需要更改标准文本。

请注意,这些更改并未出现在 2018 年发布的N4762 标准草案中。

我不确定标准应该如何解决这个问题;.then语义对于 a 是合理的,但shared_future对于 a不合理future,并且不同的语义会令人惊讶。

于 2018-08-29T18:00:58.803 回答