0

Compiling with

$ g++ -std=c++0x -I "inc" src/*.cpp

and receiving

src/ProcessGroup.cpp:25:10: error: no matching constructor for initialization of 'std::__1::thread'
  thread t(&Process::Run, p, exit_code);
         ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:349:9: note: candidate template
      ignored: couldn't infer template argument '_Fp'
thread::thread(_Fp&& __f, _Args&&... __args)
        ^

g++ is complaining that it cannot find a matching constructor for the arguments I give it:

void
ProcessGroup::Add(Process *p)
{
  Process::status_t *exit_code = new Process::status_t;
  thread t(&Process::Run, p, exit_code);
  instance_t *instance = new instance_t(&p, &t);
  threads.insert(pair<instance_t*, Process::status_t*> (instance, exit_code));
}

// FIXME: Should *not* be using system(); this was just a standup to
// test multithreading
Process::status_t
Process::Run() const
{
  return system(command.c_str());
}

void
Process::Run(Process::status_t &exit_code)
{
  exit_code = Run();
}

As far as I can tell, I am asking the compiler for the constructor which matches

thread( <some function>, <some object>, <some argument>... )

which should work according to this answer to Start thread with member function. It doesn't, so obviously something must be wrong, but what is it?

The entire code is available on GitHub. I apologize to people looking at this post in the future—the history of that repository will likely be rewritten.

Community
  • 1
  • 1
Sean Allred
  • 3,558
  • 3
  • 32
  • 71
  • 1
    `Process::Run` is overloaded, so you have to select an overload. – dyp Oct 03 '14 at 12:49
  • 1
    `new instance_t(&p, &t);` <--`t` is a local variable and you're taking its address. This is probably not going to go well later... – Dark Falcon Oct 03 '14 at 12:49
  • @dyp I thought it might have had something to do with that, which is why I included the overloaded definitions. How do I select one? – Sean Allred Oct 03 '14 at 12:50
  • @DarkFalcon Yeah, there's a whole lot wrong with the code! This is a prototype project and this is the first time i've compiled. Most of this was written between 1–2am. :) – Sean Allred Oct 03 '14 at 12:50
  • 1
    Use either a `static_cast` (like `static_cast(&Process::Run)` or pass a function object with overloaded `operator()` (or wrap the function). Using a lambda: `[](Process* ptr, Process::status_t& st) { ptr->Run(st); }` – dyp Oct 03 '14 at 12:50
  • Use a lambda: `std::thread t{[=]{ p->Run(*exit_code); });` or better, `std::thread t{[=]{ *exit_code = p->Run(); });` and you won't need to overload `Run`. Also, the next problem you will have is that `std::terminate` will be called from `t`'s destructor at the end of `Process::Add`: a joinable thread must be joined or detached before the thread object is destroyed. – Casey Oct 03 '14 at 15:06

1 Answers1

3

You want:

std::thread t(static_cast<void(Process::*)(Process::status_t&)>(&Process::Run),
              p, std::ref(*exit_code));

Since your member function is overloaded, you need to specify the desired overload explicitly. Note also the reference: objects of std::thread own all their bound state, so reference semantics to outside state have to be made explicit. And you need to dereference the pointer exit_code, of course.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Thank you, and sorry for the delay in accepting. The error I ran up against (after this one) ended up having nothing to do with this particular issue. :) – Sean Allred Oct 03 '14 at 23:58