使用std :: thread调用重载的成员函数

Ram*_*Ram 11 c++ c++11 stdthread visual-studio-2012

对于需要使用线程跨越的函数,是否可能存在重载?

我有一个名为Complex的简单类.

class Complex
{
public:
    Complex():realPart_(0), imagPart_(0){}

    Complex(double rp, double ip) : realPart_(rp), imagPart_(ip) {}

    double & real() { return realPart_;}
    double & imag() { return imagPart_;}

    const double & real() const { return realPart_;}
    const double & imag() const { return imagPart_;}

    double square() const {return realPart_*realPart_ - imagPart_*imagPart_;}

    void display() const
    {
        std::cout << "Square of the Complex number (" << realPart_ << ") + i (" << imagPart_ << " ) is " << square() << std::endl;  
    }

    void display(unsigned nTimes) const {while(nTimes-- > 0)display();}

private:

    double realPart_;
    double imagPart_;

};

void Test3()
{
    Complex c1(1, 0.74), c2(2, 0.35);

    std::thread sqCalc1(&Complex::display, &c1);
    std::thread sqCalc2(&Complex::display, &c2);

    sqCalc1.join();
    sqCalc2.join();
}
Run Code Online (Sandbox Code Playgroud)

构建此代码时出错.

error C2661: 'std::thread::thread' : no overloaded function takes 2 arguments
Run Code Online (Sandbox Code Playgroud)

如果没有重载的显示函数采用unsigned,那么我显示的代码工作正常.

Jon*_*ely 13

问题与无关std::thread(错误是误导性的),可以通过重新排列代码来显示:

auto memfunc = &Complex::display;
std::thread sqCalc1(memfunc, &c1);
std::thread sqCalc2(memfunc, &c2);
Run Code Online (Sandbox Code Playgroud)

错误现在在第一行,因为正如其他答案所说,表达式&Complex::display引用了一个重载函数,编译器不知道你的意思.

您可以通过告诉编译器您要调用的函数的类型,使用强制转换或类似的方式来选择所需的重载:

void (Complex::*memfunc)() const = &Complex::display;
std::thread sqCalc1(memfunc, &c1);
std::thread sqCalc2(memfunc, &c2);
Run Code Online (Sandbox Code Playgroud)

现在您已明确请求display返回的重载void并且不带参数.

如果您的编译器支持C++ 11别名声明,那么您可以更容易阅读:

using memfunc_type = void (Complex::*)() const;
memfunc_type memfunc = &Complex::display;
std::thread sqCalc1(memfunc, &c1);
std::thread sqCalc2(memfunc, &c2);
Run Code Online (Sandbox Code Playgroud)


bil*_*llz 5

lambda可以在这里使用,您可以调用任何对象函数并传递参数:

int main()
{
    Complex c1(1, 0.74), c2(2, 0.35);

    std::thread sqCalc1([=]{c1.display();});
    std::thread sqCalc2([=]{c2.display(3);});

    sqCalc1.join();
    sqCalc2.join();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)


Arn*_*rtz 5

与此问题的一些评论相反,这不是C++ 11限制ctor参数列表的问题,也不是编译器问题.std :: thread构造函数可以使用指向成员函数的指针,然后是调用成员函数的对象引用/指针,后跟成员函数参数(如果有的话).

手头的问题只是一个消歧问题,只是通过看&Complex::display,编译器没有机会知道你所指的哪个重载,因为在扣除模板参数时它不知道在构造函数内部将调用函数指针.其他参数,因此只有一元或0元成员函数才有意义.

2 bluescarni和billz已经展示了可能的解决方案:

  1. 将lambda传递给线程的构造函数,因为在lambda内部重载决策可以确定调用显示函数.
  2. 将成员函数指针强制转换为正确的函数指针类型,因此编译器知道要选择哪一个用于模板参数推导.

第三种可能性是显式指定函数指针的模板参数,但遗憾的是,无法显式实例化模板化构造函数:

std::thread sqCalc1<Complex::*()const>(&Complex::display, &c1); //doesn't work
Run Code Online (Sandbox Code Playgroud)

但是,这对显式演员和参数演绎没有太大影响.我总是喜欢使用lambdas,在所有情况下,即使没有这种歧义,只是因为你可以在函数调用之前放置一个断点.