c++ - 通过完美转发将可变参数模板参数作为对 std::thread 的引用传递

标签 c++ c++11 templates variadic-templates

<分区>

考虑这个简单的可变参数模板函数,它生成一个线程并将参数转发给线程函数。 为什么我在这里的线程构造函数上会出现模板替换失败?

std::thread t;

void test3(int& a)
{
    a = 10;
}

template<class ...Args>
void test(Args&&... args)
{
   t = std::thread(test3, std::forward<Args>(args)...);
}

int main()
{
    auto timer = 2s;

    int a = 1;
    test(a);
    std::this_thread::sleep_for(timer);
    std::cout << a << std::endl;
    t.join();
}

编译器输出:

template argument deduction/substitution failed:
/opt/wandbox/gcc-head/include/c++/8.0.0/bits/invoke.h: In substitution of 
'template<class _Callable, class ... _Args> constexpr typename 
std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, 
_Args&& ...) [with _Callable = void (*)(int&); _Args = {int}]':
/opt/wandbox/gcc-head/include/c++/8.0.0/thread:233:29:   required by 
substitution of 'template<long unsigned int ..._Ind> decltype 
(std::__invoke(_S_declval<_Ind>()...)) std::thread::_Invoker<std::tuple<void 
(*)(int&), int> >::_M_invoke<_Ind ...>(std::_Index_tuple<_Ind1 ...>) [with 
long unsigned int ..._Ind = {0, 1}]'
/opt/wandbox/gcc-head/include/c++/8.0.0/thread:240:2:   required from 
'struct std::thread::_Invoker<std::tuple<void (*)(int&), int> >'
/opt/wandbox/gcc-head/include/c++/8.0.0/thread:127:22:   required from 
'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)
 (int&); _Args = {int&}]'
prog.cc:23:14:   required from 'void test(Args&& ...) [with Args = {int&}]'
prog.cc:43:11:   required from here
/opt/wandbox/gcc-head/include/c++/8.0.0/bits/invoke.h:89:5: error: no type 
named 'type' in 'struct std::__invoke_result<void (*)(int&), int>' 

当我用这样的 std::ref 包装参数的转发时:

std::thread(test3, std::ref(std::forward<Args>(args)...));

它有效。论点不是应该首先完美转发吗?

最佳答案

默认情况下线程复制它的参数。另一种选择是疯狂,因为对本地数据的引用往往不太可能持续整个线程的生命周期。

如果你想,如果你真的想传递一个引用,用 std::ref 包装它:

test(std::ref(a));

现在,您的代码仍然表现出未定义的行为; sleep 不同步访问,所有不同步的读/写只是未定义的行为。

对于具体的“非恶意”示例,编译器可以自由假设 amain 中保持不变,直到 join 之后您进行的第一个同步操作,因此可以忽略所有非本地影响,并且不会在本地进行修改。

他们可能无法检测到这种优化,并且您未定义的行为可能会导致您想要发生的事情发生,但鼻恶魔可以任何

所以在 join 之后移动打印。


这是 C++。变量生命周期管理是程序员的工作。隐式地在线程之间悬挂引用是一个非常糟糕的主意。

关于c++ - 通过完美转发将可变参数模板参数作为对 std::thread 的引用传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45404939/

相关文章:

c++ - 当我使用 long long int 和 int 作为参数时,为什么 max 函数会出现错误

c++ - gcc 的 asm volatile 是否等同于递归的 gfortran 默认设置?

c++ - 类模板中 std::array 的大小取决于模板参数

c++ - 允许模板参数仅为某些类型并根据它决定操作

python - 比较 django 模板中的两个日期时间字段

c++ - 仅使用标准库创建 "Vector of References"的标准实践

c++ - ROS C++ 项目 "include"文件夹?

c++ - 在右值引用参数上使用 std::move 的原因

c++ - 为什么这里调用复制构造函数,而不是 move 构造函数?

c++ - 为什么无符号短(乘)无符号短转换为有符号整数?