16

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.

4
  • I do. This was just an example to demonstrate the problem. Commented Jan 11, 2013 at 10:47
  • AFAIK std::thread constructor only supports static function pointers or appropriate functor classes as parameter. To call class member methods, you'll need a wrapper class that keeps the actual class instance along with the function pointer to call. Commented Jan 11, 2013 at 10:51
  • makulik, thanks for your reply. What I want to know is Is this a restriction imposed by the C++ standard or the compiler vendors are yet to get around this problem. Commented Jan 11, 2013 at 10:55
  • @g-makulik, no, std::thread supports calling member functions directly. The problem is that &Complex::display is ambiguous, not a problem with std::thread Commented Jan 13, 2013 at 18:50

5 Answers 5

24

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);
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks! I have also found that the order of functions declared in .h is important: it should go from less arguments to overloaded functions with more arguments.
@MickeyTin in general that's not true, the order doesn't matter. It certainly doesn't matter in this instance.
That what I observed, I wasn't able to compile until I changed the order. The compiler kept complaining about wrong arguments number until I switched the functions. I'm building Android NDK project.
You saved my day. However, I think the thread class should be able to handle overloaded member functions since the compiler has all the information required at build time. There is no possible reason than being just "inconsiderate". I'll simply avoid overloading for multuthreading candidates.
@Jake'Alquimista'LEE but std::thread is just a library type, that you could write yourself in pure C++. The compiler doesn't know that std::thread{&Complex::display, &c1} is going to call that member with no arguments. It's opaque to the compiler, and no different to some_arbitrary_function(&Complex::display, &c1). There is simply no way in the C++ language to pass an overloaded function as a function argument, so std::thread can't do it, and your own functions can't do it.
6

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

6 Comments

That is a nice workaround. But I want to know why there is no support for overloaded member functions. Is it not possible to provide such support or they are yet to provide the same ?
WTH do you exactly mean with 'overloaded member function'?? I can't see any 'overloading' demonstrated in your code.
void display(), void display(unsigned nTimes) are two functions on Complex class that have the same name but different parameters.
@g-makulik he has display which is overloaded but using lambda and std::thread has no issue at all
Your first sentence is wrong now. The syntax is perfectly fine if the function is not overloaded and that is basically what he is asking. See here: stackoverflow.com/questions/10673585/…
|
6

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.

Comments

4

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

1 Comment

When I test the cast, it compiles ok but crashes when execute it.
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.