我尝试使用指向函数的指针(不是指向成员函数的指针)调用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可以解决问题;我想了解问题出现的原因。
答案 0 :(得分:6)
std::thread
存储传递的参数的副本。其中Massimiliano Janes pointed out在调用者的上下文中被评估为临时的。出于所有意图和目的,最好将其视为const对象。
由于x
是一个非const引用,它不能绑定到线程提供给它的参数。
如果您希望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
将动态创建它。
答案 1 :(得分:3)
std :: thread构造函数在调用可调用的完全转发结果之前对其参数执行decay_copy;在你的foo中,你试图将左值引用(int&amp; x)绑定到右值引用(到临时),因此错误;要么采取一个int,一个int const&amp;或者是一个int&amp;&amp;相反(或传递参考包装)。
答案 2 :(得分:2)
继StoryTeller's answer之后,lambda可能会提供更明确的方式来表达这一点:
我认为有几种情况:
如果我们确实想在外部范围内传递对<option value="'.$read.'">'.$read.'</option>
的引用:
i
如果foo参考恰好是一个历史性事故:
auto thd = std::thread([&i]
{
foo("bar", i);
});
在第二种形式中,我们已经对变量 auto thd = std::thread([]() mutable
{
int i = 1;
foo("bar", i);
});
进行了本地化,并降低了它将被读取或写入线程外部(可能是UB)的风险。