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

时间:2013-01-11 10:43:44

标签: c++ c++11 visual-studio-2012 stdthread

是否可以为需要使用线程跨越的函数进行重载?

我有一个名为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();
}

构建此代码时出错。

error C2661: 'std::thread::thread' : no overloaded function takes 2 arguments

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

5 个答案:

答案 0 :(得分:10)

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

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

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

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

void (Complex::*memfunc)() const = &Complex::display;
std::thread sqCalc1(memfunc, &c1);
std::thread sqCalc2(memfunc, &c2);

现在您明确请求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);

答案 1 :(得分:5)

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

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

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

  1. 将lambda传递给线程的构造函数,因为在lambda重载决策中可以确定调用显示函数。
  2. 将成员函数指针强制转换为正确的函数指针类型,因此编译器知道要选择哪一个用于模板参数推断。
  3. 第三种可能性是明确指定函数指针的模板参数,但遗憾的是it is not possible to explicitly instantiate templated constructors:

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

    然而,这对显式演员和参数演绎没有多大影响。无论如何,我喜欢使用lambdas,在所有情况下,即使没有这样的歧义,只是因为你可以在函数调用之前放置一个断点。

答案 2 :(得分:4)

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;
}

答案 3 :(得分:4)

也许typedeffing和cast可以帮忙吗?

typedef void (Complex::*display_0)() const;
typedef void (Complex::*display_1)(unsigned) const;

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

答案 4 :(得分:0)

虽然它不是要重写成员函数,但感谢@billz的lambda解决方案的唯一方法是使用“my”代码,这是线程调用问题的最简单的情况再次,如上所述,用lambdas解决了。

#include <thread>
void f(int a){}
void f(int a, int b){}

int main()
{
   std::thread t([=]{ f(2); });
   t.join();

   return 0;
}