16

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

我有一个名为 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

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

4

5 回答 5

22

问题与问题无关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);
于 2013-01-13T18:56:37.493 回答
6

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;
}
于 2013-01-11T10:49:26.750 回答
6

与对该问题的一些评论相反,这不是 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

但是,这不会对显式强制转换和参数推导产生太大影响。而且我更喜欢在所有情况下使用 lambda,即使没有这种歧义,只是因为您可以在函数调用之前放置一个断点。

于 2013-01-11T13:59:02.077 回答
4

也许 typedefing 和 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);
于 2013-01-11T13:14:32.293 回答
0

虽然它不是关于覆盖成员函数,但感谢 @billz 提供 lambda 解决方案的唯一方法是贡献“我的”代码,这是线程调用问题的最简单情况,再次使用上面提出的 lambdas 解决。

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

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

   return 0;
} 
于 2015-04-23T08:20:29.303 回答