调用 std::线程,指针指向独立函数

Invoking std::thread with pointer to freestanding function

本文关键字:独立 函数 std 线程 调用 指针      更新时间:2023-10-16

我试图用指向函数的指针(而不是指向成员函数的指针)调用std::thread完美的转发构造函数(template< class Function, class... Args > explicit thread( Function&& f, Args&&... args );),如以下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存储它所传递的参数的副本。正如马西米利亚诺·简斯(Massimiliano Janes)指出的那样,这是在临时呼叫者的背景下进行评估的。出于所有意图和目的,最好将其视为 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();
}

现场示例

实用程序std::ref将动态创建它。

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

继StoryTeller的回答之后,lambda可能会提供一种更清晰的方式来表达这一点:

我认为有几种情况:

如果我们确实想在外部作用域中传递对i的引用:

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

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

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

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