使用线程可变参数模板构造函数时发生错误

An error occur when using a thread variadic template constractor

void f(vector<int>& v){
    for(const auto& x:v) cout << x;
}

class F{
private:
    vector<int> v;
public:
    F(vector<int>& vc):v{vc}{}
    void operator()(){
        for(const auto& x:v) cout << x;
    }
};

int main()
{
    vector<int> some_vec{3,5,77,32,1};
    vector<int> vec{66,8,90,45,777};
    thread t1{f,some_vec};
    thread t2{F(vec)};
    t1.join();
    t2.join();
    cout << '\n';
}

发生错误“'class std::result_of< void (*(std::vector))(std::vector&)>' 中没有名为 'type' 的类型

如果f中的参数向量声明为constvoid f(const vector<int>& v),则错误消失。

另一方面,带有函数对象 F 的代码工作得很好。

来自 Bjarne Stroustrup 的代码——C++ 编程语言 5.3.2 传递参数

std::thread 存储传递给其构造函数的参数的副本,然后使用这些副本的右值作为处理程序的参数。也就是说,函数 f 不能用 std::vector 的右值调用,因为它需要一个非常量左值引用。即使您将其更改为 const 左值引用,它也是实际传递给 t1 的构造函数的内容的副本。

相反,class F 有一个隐式定义的复制构造函数,它的函数调用运算符不需要参数,因此不会出错。 (并且 F 本身是在传递给线程的构造函数之前构造的)。

如果您希望函数 fsome_vec 实例上运行,您必须使用引用包装器对其进行包装:

#include <functional>

std::thread t1{f, std::ref(some_vec)};
//                ~~~~~~~^