4

我很难找到如何使用std::thread()lambdas。即,具有可变参数 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:不编译

我不明白:

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

2 回答 2

2

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

于 2018-11-14T13:25:27.787 回答
1

尝试

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 && ...而不是T && .... 或者,也许,T const & ...

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

当你写

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

&&通用引用并T...成为int, 当你打电话foo(1), 和int &, 当你打电话foo(n)

在你得到的函数里面

[](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 &) 并获取一个int左引用变量,但不适用于第二次调用,因为将(so a right-reference, )的副本std::thread传递给等待左引用的 lambda。std::forward<int>(t)int &&

于 2018-11-14T12:44:53.157 回答