Calling overloaded member functions using std::thr

2019-02-16 13:25发布

Is it possible to have overloads for functions that we need to span using threads ?

I have a simple class called 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();
}

I get errors when I build this code.

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

If there is no overloaded display function that takes an unsigned then the code I have shown works fine.

5条回答
手持菜刀,她持情操
2楼-- · 2019-02-16 14:19

Contrary to some comments on the question, this is not a problem of C++11 restricting the ctor argument list, nor is it a compiler problem. std::thread constructor may take a pointer-to-member-function, followed by the object reference/pointer on wich the member function shall be called, followed by member function arguments (if there are any).

The problem at hand is just a disambiguation issue, just by seeing &Complex::display, the compiler has no chance to knwo which of the overloads you mean, because while deducting the template arguments it does not know that inside the constructor the function pointer will be called with the other arguments and that therefore only the unary or 0-ary member function makes sense.

2 Possible solutions have been shown by bluescarni and billz:

  1. Pass a lambda to the thread's constructor, because inside the lambda overload resolution can determine wich display function gets called.
  2. Cast the member function pointer to the correct function pointer type, so the compiler knows which one to pick for template argument deduction.

A third possibility would be to explicitly specify the template parameter of the function pointer, but sadly it is not possible to explicitly instantiate templated constructors:

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

However, this would not make much difference to the explicit cast and argument deduction. and I prefer using lambdas anyways, in all cases, even if there is no such ambiguity, just because you can put a breakpoint right before the function call.

查看更多
女痞
3楼-- · 2019-02-16 14:20

Maybe typedeffing and casting could help?

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楼-- · 2019-02-16 14:25

lambda can be used here, you could call any object function and pass arguments in as well:

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;
}
查看更多
放荡不羁爱自由
5楼-- · 2019-02-16 14:28

The problem is nothing to do with std::thread (the error is misleading), as can be shown by rearranging the code:

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

The error will be on the first line now, because as other answers have said, the expression &Complex::display refers to an overloaded function and the compiler doesn't know which one you mean.

You can select the desired overload by telling the compiler the type of the function you are trying to call, with a cast or like this:

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

Now you've explicitly requested the display overload that returns void and takes no arguments.

If your compiler supports C++11 alias declarations you can make that easier to read:

using memfunc_type = void (Complex::*)() const;
memfunc_type memfunc = &Complex::display;
std::thread sqCalc1(memfunc, &c1);
std::thread sqCalc2(memfunc, &c2);
查看更多
该账号已被封号
6楼-- · 2019-02-16 14:32

Although it is not about overriding member function, the only way to thank @billz for the lambda solution is to contribute with "my" code, that is the simplest case of the thread-call problem, again, solved with lambdas as proposed above.

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

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

   return 0;
} 
查看更多
登录 后发表回答