【问题标题】:Using boost::future with continuations and boost::when_all使用带有延续和 boost::when_all 的 boost::future
【发布时间】:2014-05-05 01:11:57
【问题描述】:

我想使用boost::futureboost::when_all / boost::when_any

Boost trunk - 不是 1.55 - 包括后者的实现(仿照 here 提案,即将用于 C++14/17 和 Boost 1.56)。

This 是我所拥有的(并且它无法编译):

#include <iostream>

#define BOOST_THREAD_PROVIDES_FUTURE
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
#define BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY
#include <boost/thread/future.hpp>

using namespace boost;

int main() {
   future<int> f1 = async([]() { return 1; });
   future<int> f2 = async([]() { return 2; });

   auto f3 = when_all(f1, f2);

   f3.then([](decltype(f3)) {
      std::cout << "done" << std::endl;
   });

   f3.get();
}

Clang 3.4 使用 this 退出 - 这是一段摘录:

/usr/include/c++/v1/memory:1685:31: error: call to deleted constructor of 'boost::future<int>'
::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);

是我做错了还是这是一个错误?

【问题讨论】:

  • 我认为你需要getthen返回的future而不是f3,即auto f4 = f3.then(...); f4.get();
  • 如果我阅读正确找到的源代码,when_all 会使用迭代器。您没有使用迭代器。您是否尝试将期货放入向量中并改为调用when_all(vec.begin(), vec.end())
  • gist.github.com/oberstet/9785331 完全相同的问题(“调用已删除的构造函数”)另外,至少链接的提案(论文)提到了when_all 的2 个重载版本.. 一个采用位置参数,其他迭代器。
  • gist.github.com/oberstet/9785331 有同样的问题,因为来自std::intializer_liststd::vector 构造函数试图复制期货。

标签: c++ c++11 boost future continuations


【解决方案1】:

问题是when_all 只能用右值futureshared_future 调用。来自N3857

template <typename... T> 
see below when_all(T&&... futures); 

要求: T 的类型为 future&lt;R&gt;shared_future&lt;R&gt;

由于引用折叠规则,传递左值会导致T 被推导出为future&lt;T&gt;&amp;,这违反了规定的要求。 boost 实现不会检查此前提条件,因此您会在模板代码深处得到一个错误,其中应该是右值未来的移动变成了左值未来的尝试副本。

您需要将期货移入when_all 参数:

auto f3 = when_all(std::move(f1), std::move(f2));

或者一开始就避免命名它们:

auto f = when_all(async([]{return 1;}),
                  async([]{return 2;}));

另外,您必须 getthen 返回的未来而不是中间未来:

auto done = f.then([](decltype(f)) {
  std::cout << "done" << std::endl;
});

done.get();

因为你调用 then 的未来被移动到延续的参数中。来自N3857中then的描述:

后置条件:

  • future对象移动到延续函数的参数中

  • valid() == false 在原始future 对象返回后立即出现

每 30.6.6 [futures.unique_future]/3:

在未定义valid() == falsefuture 对象上调用除析构函数、移动赋值运算符或valid 之外的任何成员函数的效果。

您可以通过完全避免命名期货来避免 c++14 中的大多数这些问题:

when_all(
  async([]{return 1;}),
  async([]{return 2;})
).then([](auto&) {
  std::cout << "done" << std::endl;
}).get();

【讨论】:

  • 我唯一想知道的是为什么允许我两次移动未来.. 请参阅上面链接的代码。它将f2 移动到when_all,得到f12,第二次移动到when_all,得到f23。您能解释一下为什么允许/有效吗?非常感谢!
  • @oberstet 移出的对象并非无效,它处于“有效但未指定的状态”。您可以反复从对象移动,但这样做的结果是实现定义的。
  • @oberstet 对上述内容进行小幅更正,除非另有说明,否则标准库对象通常如此:从 30.6.6 [futures.unique_future]/3 "调用除析构函数、移动赋值运算符或 future 对象上的 valid,其中 valid() == false 未定义。"
  • 非常感谢!这是无价的.. 为这一切奋斗了 2 个小时。
  • @oberstet 修正了答案:我对解决方案是正确的,但对问题并不完全正确。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-05
  • 2018-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多