使用指向独立函数的指针调用 std::thread

Invoking std::thread with pointer to freestanding function

我尝试调用 std::thread 完美转发构造函数 (template< class Function, class... Args > explicit thread( Function&& f, Args&&... args );) 并带有指向函数的指针(不是指向 member 函数的指针),如图所示在以下 M(N)WE 中:

#include <thread>
#include <string>

static void foo(std::string query, int & x)
{
  while(true);
}

int main() {
 int i = 1;
 auto thd = std::thread(&foo, std::string("bar"), i);
 thd.join();
}

现场演示:https://godbolt.org/g/Cwi6wd

为什么代码无法在 GCC、Clang 和 MSVC 上编译,抱怨缺少 invoke(或类似名称)的重载? 函数参数是指向函数的指针,所以它应该是一个Callable,对吗?

请注意:我知道使用 lambda 可以解决问题;我想了解为什么会出现这个问题。

std::thread 存储传递给它的参数的副本。作为 ,在临时调用者的上下文中进行评估。出于所有意图和目的,最好将其视为 const 对象。

由于 x 是一个非常量引用,它不能绑定到线程提供给它的参数。

如果要x引用i,需要使用std::reference_wrapper.

#include <thread>
#include <string>
#include <functional>

static void foo(std::string , int & )
{
  while(true);
}

int main() {
 int i = 1;
 auto thd = std::thread(foo, std::string("bar"), std::ref(i));
 thd.join();
}

Live Example

实用程序 std::ref 将即时创建它。

std::thread 构造函数在调用可调用对象之前对其参数执行 decay_copy——将结果完美转发给它;在您的 foo 中,您正试图将左值引用 (int& x) 绑定到右值引用(临时值),因此出现错误;取而代之的是 int、int const& 或 int&&(或传递引用包装器)。

之后,lambda 可能提供更清晰的表达方式:

我认为有两种情况:

如果我们真的想在外部范围内传递对 i 的引用:

 auto thd = std::thread([&i]
 {
     foo("bar", i);
 });

如果 foo 引用恰好是一个历史事故:

 auto thd = std::thread([]() mutable
 {
     int i = 1;
     foo("bar", i);
 });

在第二种形式中,我们对变量进行了本地化 i 并降低了它在线程外(即 UB)被读取或写入的风险。