1
#include <thread>
#include <iostream>
using namespace std;

class A
{
    public:
    A(){}
    void m(std::string* s)
    {
     cout<<*s;
    }
    void m(std::string s)
   {
     cout<<s;
   }
};    

int main()
{
 A a;
 string str="hi!\n";
 std::thread(&A::m,a,&str);

}

this doesn't compile; it gives:

error: no matching function for call to ‘std::thread::thread(<unresolved overloaded function type>, A&, std::string*)’

if I remove the second member it compiles! why? I can't use overloaded methods in std::thread?

1 Answer 1

6

You can, but you have to pick the desired overload manually:

std::thread th(static_cast<void (A::*)(std::string*)>(&A::m),a,&str);

Or you could use a lambda:

std::thread th([&] { a.m(&str); });

Addendum: The reason this can't be deduced automatically is, in short, that the compiler looks only skin-deep when searching for the right constructor. Finding (making!) the right constructor from the relevant constructor template of the std::thread class involves template argument deduction, and template argument deduction looks, as a rule, only at the signatures and not the internals of a function template (in this case a constructor template, which is for our purposes the same). The relevant constructor template is

template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );

...which does not in itself say anything about the interplay of f and args in the depths of the implementation. There is not enough information in it to decide that only one overrload of A::m can work, so the ambiguity cannot be resolved, and you have to do it manually.

Whether it is actually possible and/or practical to make the compiler look deeper to resolve such ambiguities is an interesting question. I imagine it would be quite a challenge. Either way, it has not yet been done.

Sign up to request clarification or add additional context in comments.

6 Comments

@volperossa The error has nothing to do with std::thread. &A::m itself is ambiguous because the compiler doesn't know which m you're referring to.
I extended the answer a bit to address that. Superficially, because explaining template argument deduction in detail is tedious; the rules are fairly complex. There's a link, if you're interested.
@volperossa: If std::thread's constructor were a part of the core language then, yes. But it's not. It's just a function from a library (albeit the standard library). It has to conform to the rules of the language and without any special treatment &A::m is ambiguous here. The language doesn't know that it could theoretically figure out which overload to use from the other arguments, because it has no idea what those arguments mean.
What the constructor does is roughly equivalent to: auto f = &A::m; auto obj = a; auto arg = &str; (obj.*f)(arg); and it can't determine the type of f in the first statement. The function call that happens later is too late to influence the type deduction that is needed for auto f = &A::m;
thanks! just a thing: std::thread th(static_cast<void (A::*)(std::string*)>(&A::m),a,&str); the second parameter would be a pointer to the object owner of the method...so..it wouldn't be &a?
|

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.