【问题标题】:Forward variadic argument to thread with lambda使用 lambda 将可变参数转发给线程
【发布时间】:2018-11-14 12:07:03
【问题描述】:

我无法找到如何将 std::thread() 与 lambda 一起使用。即,具有可变参数 lambda 通过转发接收参数。举个例子:

template<typename... T> 
auto foo(T&&... t){
    [](T&&... t){}(std::forward<T>(t)...); // (1)

    return std::thread( // (2) 
        [](T&&... t){},
        std::forward<T>(t)...
    );
}

auto bar(){
    int n=1;
    foo(1); (A)
    foo(n); (B)
}

A.1:编译

A.2:编译

B.1:编译

B.2:无法编译

我不明白:

  • 为什么使用 (B) 的 std::thread() (2) 版本无法编译而 (A.2) 可以编译?
  • 为什么 (B.1) 和 (B.2) 之间存在差异

【问题讨论】:

  • 应该是std::forward&lt;T&gt;(t)...。我不确定这对你的情况有帮助,因为你有一个单元素包,但仍然。
  • 我认为这与错误仍然存​​在但编辑为具有更清晰的语法ty相同

标签: c++ multithreading c++14 variadic-templates generic-lambda


【解决方案1】:

std::thread 不能简单地将其参数通过引用转发给 lambda,因为这意味着两个线程可能在不同步的情况下同时访问参数。因此,std::thread 创建了参数的临时副本,并将它们传递给 lambda。因为它们是临时的,所以它们是右值。这在 A.2 中有效,因为 lambda 的参数是一个右值引用(因为 Tint,所以 T&amp;&amp;int&amp;&amp;)。它在 B.2 中不起作用,因为 lambda 的参数是左值引用(因为 Tint&amp;,所以 T&amp;&amp;int&amp;)。正如 max66 所说,您可能想在您的 lambda 中使用 auto&amp;&amp;... 以便它可以接受传递给它的任何内容。

【讨论】:

    【解决方案2】:

    试试

    template<typename... T> 
    auto foo(T&&... t){
        [](T&&... u){ }(std::forward<T>(t)...); // (1)
    
        return std::thread( // (2) 
            [](auto &&... u){ },
            std::forward<T>(t)...
        );
    }
    

    我的意思是:在 lambda 中,您传递给 std::thread()auto &amp;&amp; ... 而不是 T &amp;&amp; ...。或者,也许,T const &amp; ...

    我不是语言层,也许有人可以纠正我,但在我看来,通用引用和右值引用之间存在冲突。事实上,std::thread() 将以下参数的副本传递给第一个参数。

    当你写作时

    template<typename... T> 
    auto foo(T&&... t)
    

    &amp;&amp; 是通用引用,当您调用 foo(1) 时,T... 变为 int,当您调用 foo(n) 时,int &amp;

    在你得到的函数内部

    [](int){ }(std::forward<int>(t)); // (1)
    
    return std::thread( // (2) 
        [](int){ },
        std::forward<int>(t)...
    );
    

    如果f(0).

    这很有效,因为两个 lambda 都在等待 int 复制,而这永远有效。

    但是当你调用 f(n) 时,你会在 foo() 内部得到

    [](int &){ }(std::forward<int>(t)); // (1)
    
    return std::thread( // (2) 
        [](int &){ },
        std::forward<int>(t)...
    );
    

    这适用于第一次调用,因为 lambda 等待 int 左引用变量 (int &amp;) 并获得一个 int 左引用变量,但不适用于第二次调用,因为 @ 987654343@ 将std::forward&lt;int&gt;(t)(即右引用,int &amp;&amp;)的副本传递给等待左引用的 lambda。

    【讨论】:

      猜你喜欢
      • 2012-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多