线程函数中的通用引用

时间:2018-01-19 11:16:37

标签: c++

我一直在学习完美转发和使用&&在函数模板中(请参阅我的this previous question),并想知道我在Args&&下使用StartDetachedThread()是否合理:

#include <thread>

class CObject {};
void MyThreadFunc(CObject&)
{
}

// ** Will not compile with this function declaration! **
void MyThreadFunc(CObject&&)
{
}

template<typename FunctionType, typename ...Args>
void StartDetachedThread(FunctionType func, Args&&... args)
{
    thread([&]()
    {
        func(forward<Args>(args)...);
    }).detach();
}

int main()
{
    CObject object;
    StartDetachedThread(MyThreadFunc, object);

    CObject object2;
    StartDetachedThread(MyThreadFunc, std::move(object2));
    return 0;
}

这段代码只是创建一个分离的线程,运行提供的函数,并将提供的参数传递给它。

然而,VS 2017抱怨:

'StartDetachedThread': no matching overloaded function found
'void StartDetachedThread(FunctionType,Args &&...)': could not deduce template argument for 'FunctionType'

1)我知道传递给thread构造函数的参数首先被复制,然后通过引用传递给新线程,所以当我传递一个右值引用时,我尝试调用MyThreadFunc(CObject&&)去上班?

2)拥有StartDetachedThread(FunctionType&& func, Args&&... args)是否有任何价值 - &&是否需要FunctionType

3)在启动这样的线程时使用Args&&是否有任何价值,或者我应该始终使用Args吗?

2 个答案:

答案 0 :(得分:1)

问题是编译器无法推导出MyThreadFunc的哪个重载。至少有两种方法可以解决它:

  1. 重命名其中一个功能,以便更清楚您想要的功能。

  2. 使用显式模板参数:

    StartDetachedThread<void (CObject&)>(MyThreadFunc, object);
    StartDetachedThread<void (CObject&&)>(MyThreadFunc, std::move(object2));
    

答案 1 :(得分:1)

您的代码中的问题与std::thread无关,这是因为MyThreadFunc在此上下文中含糊不清:

// Which MyThreadFunc should be used?
StartDetachedThread(MyThreadFunc, object);

关于你的问题:

  

1)我知道传递给线程构造函数的参数首先被复制,然后通过引用传递给新线程,[...]

在您的示例中,唯一的副本是lambda的副本。这里不会复制参数,如果你想复制参数,你应该使用这样的东西:

std::thread(std::move(func), std::forward<Args>(args)...).detach();

...将参数转发给std::thread构造函数。

这更安全。 - 想想如果函数StartDetachedThread在线程仍在运行时结束会发生什么?

如果您使用此功能,则需要使用object1明确告诉编译器您要为std::ref调用参考版本:

CObject object;
StartDetachedThread<void (CObject&)>(MyThreadFunc, std::ref(object)); // std::ref

CObject object2;
StartDetachedThread<void (CObject&&)>(MyThreadFunc, std::move(object2));
  

2)拥有StartDetachedThread(FunctionType&& func, Args&&... args)是否有任何价值 - &&是否需要FunctionType

     

3)在启动这样的线程时使用Args&&是否有任何价值,或者我应该始终使用Args吗?

使用转发引用可以调用StartDetachedThread而无需移动所有内容。如果您使用上述方式构建std::thread,则无论如何都会为funcargs制作副本。