【问题标题】:Is there a way to use std::async with std::experimental::future?有没有办法将 std::async 与 std::experimental::future 一起使用?
【发布时间】:2017-03-16 10:37:02
【问题描述】:

注意:即使在 C++17 中,以下也是非法的!

#include <thread>
#include <future>
#include <experimental/future>

using namespace std;

int step1(experimental::future<int>)
{
    return {};
}

int step2(experimental::future<int>)
{
    return {};
}

int step3(experimental::future<int>)
{
    return {};
}

int main()
{
    return async([](){ return {}; })
        .then(step1)
        .then(step2)
        .then(step3)
        .get();
}

C++1z提供了两种future

  1. std::future
  2. std:experimental::future

但是,std::async 只返回std::future,所以上面的代码是非法的。如果std::async返回std:experimental::future,那就没问题了。

我的问题是:

有没有办法将std::asyncstd::experimental::future 一起使用,使上面的代码在C++1z 下合法?

【问题讨论】:

  • 其实the concurrency TS是不包含在C++17中的。
  • 想知道它是如何编译的,对我来说,它在包含 &lt;experimental/future&gt; 处显示错误,尽管我使用了 1z 标志

标签: c++ multithreading concurrency synchronization c++17


【解决方案1】:

有没有办法将std::asyncstd::experimental::future 结合使用,使上面的代码在C++1z 下合法?

不。 std::async 返回一个 std::future&lt;T&gt;,尽管名称如此,但它与 std::experimental::future&lt;T&gt; 完全无关。

您必须编写自己的async 版本,为您提供新的future。一个简化的版本是这样的:

template <class F, class... Args,
    class R = std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>>
std::experimental::future<R> new_async(F&& f, Args&&... args)
{
    std::experimental::promise<R> p;
    auto fut = p.get_future();

    std::thread thread([p=std::move(p), f=std::forward<F>(f),
        args=std::tuple<std::decay_t<Args>...>(std::forward<Args>(args)...)] () mutable
    {
        try 
        {
            if constexpr(std::is_void_v<R>)
            {
                std::apply(std::move(f), std::move(args));
                p.set_value();
            }
            else 
            {
                p.set_value(std::apply(std::move(f), std::move(args)));
            }
        }
        catch(...)
        {
            p.set_exception(std::current_exception());
        }
    });

    thread.detach();
    return fut;
}

这不支持像 async 这样的其他启动策略,但这只是一个开始。

【讨论】:

  • @T.C.谢谢!真的想要Regular Void...至少if constexpr让它更容易,但仍然。
  • 哈哈。一件事导致另一件事和所有:)
  • @T.C. :您是否出于任何特殊原因使用args=std::tuple&lt;std::decay_t&lt;Args&gt;...&gt;(std::forward&lt;Args&gt;(args)...) 而不是args=std::make_tuple(std::forward&lt;Args&gt;(args)...)?这不会阻止std::reference_wrapper&lt;T&gt; -> T&amp; 转换吗?或者这是一件好事?
  • @ildjarn 这就是std::async 所做的;我只是跟风。 (作为奖励,它使R 更容易编写:P)
  • @T.C.与这个问题无关,但是您如何看待this question?我认为发布的答案不正确。
【解决方案2】:

seems likestd::experimental::futurestd::future 具有相同的构造函数,因此应该可以从std::future 构造std::experimental::future。然而,正如pointed out by ildjarn 它实际上不是根据the latest draft,所以在TS 相应更改之前似乎没有办法做到这一点。

【讨论】:

  • std::experimental::future 通过std::experimental::future 构造自身,而不是std::future。请参阅您引用的文档的以下内容。
  • @xmllmx 这意味着你永远不能构造一个std::experimental::future,因为你需要已经有一个std::experimental::future。注释说 “对于其他构造函数,请参阅 std::future 构造函数的文档。” 这意味着 std::experimental::future 具有 std::future 具有的所有构造函数,并且 另外一个需要std::experimental::future。不过,这应该与当前的草案进行核对。
  • 当前草稿is not free;最后一篇免费论文是P0159,它清楚地表明std::future 没有no 构造函数或转换。 std::experimental::futurepromisepackaged_taskmake_ready_future 等在命名空间std::experimental::concurrency_v1 中构造而成。
  • 至于“似乎std::experimental::futurestd::future 具有相同的构造函数”:不,其构造函数的指定方式相同(就先决条件而言,例外抛出、noexcept 等)为std::future,但std::experimental::future 的复制/移动构造函数必须必要采用std::experimental::future 以便成为副本/移动构造函数。 ;-]
  • 也许我不应该走捷径来编写文档。但是,是的,没有转换。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-20
  • 1970-01-01
相关资源
最近更新 更多