4

I have a place where things work using boost::thread(example using boost::asio)

  std::vector<boost::shared_ptr<boost::thread> > threads;
  for (std::size_t i = 0; i < io_services_.size(); ++i)
  {
    boost::shared_ptr<boost::thread> thread(new boost::thread(
          boost::bind(&boost::asio::io_service::run, io_services_[i])));
    threads.push_back(thread);
  }

If I try to use it with std:thread I get compile error:

std::vector<std::thread> threads;
for (std::size_t i = 0; i < this->ioServices.size(); ++i)
{
    std::thread thread(&boost::asio::io_service::run, ioServices[i]); // compile error std::thread::thread : no overloaded function takes 2 arguments   

    threads.push_back(std::move(thread));
}
Gmt
  • 569
  • 1
  • 5
  • 19
  • Relevant : http://stackoverflow.com/questions/10555566/is-there-any-difference-between-c11-stdbind-and-boostbind – Bartek Banachewicz Nov 20 '12 at 15:20
  • Your compile error doesn't contain a call to `boost::bind`? – Chad Nov 20 '12 at 15:21
  • @BartekBanachewicz updated the title, as this is pertaining to difference between boost::tread and std::thread – Gmt Nov 20 '12 at 15:27
  • @Chad tnx for pointing that out. updated – Gmt Nov 20 '12 at 15:27
  • I still don't see the update. You're calling the `std::thread` constructor with two arguments that it's not expecting. If you instead constructed a `boost::bind` object with those same two parameters, I would expect this to compile and work. – Chad Nov 20 '12 at 15:32

1 Answers1

2

In theory, both should work, since std::thread has a vararg constructor which basically invokes its arguments as if it were used with std::bind. The problem appears to be that, at least in my implementation (gcc 4.6.3), neither std::thread nor std::bind can determine which overload of run was intended, resulting in a compilation error.

However, if you use boost::bind, this works. So I would use, and manually perform the bind manually:

std::vector<std::thread> threads;
for (std::size_t i = 0; i < this->ioServices.size(); ++i)
{
    std::thread thread(boost::bind(&boost::asio::io_service::run, ioServices[i])); 

    threads.push_back(std::move(thread));
}

Edit: It appears that boost::bind succeeds because it's got a ton of overloads, and based on the number of arguments it was provided, during overload resolution and template substitution of boost::bind it can determine which overload of boost::asio::io_service::run was intended.

However, since std::bind and std::thread rely on a vararg tempalte arguments, both overloads of run are equally valid, and the compiler cannot resolve which one to use. This ambiguity results in a failure to determine which results in the failures you are seeing.

So another solution is:

std::vector<std::thread> threads;
typedef std::size_t (boost::asio::io_service::*signature_type)();
signature_type run_ptr = &boost::asio::io_service::run;

for (std::size_t i = 0; i < this->ioServices.size(); ++i)
{
    std::thread thread(run_ptr, ioServices[i]); 

    threads.push_back(std::move(thread));
}
Dave S
  • 20,507
  • 3
  • 48
  • 68
  • what I find interesting here is that io_service::run is not a static method and don't know how boot::bind can bind to that... – Gmt Nov 20 '12 at 15:57
  • the first solution proposed works also. at least it compiles under vs2012 – Gmt Nov 20 '12 at 15:59
  • 2
    @Gmt: `boost::bind` (and `std::bind`) work with Pointer to Member Functions by assuming that the first argument provided (either at bind time or invocation time) is either a reference or pointer to the appropriate type, and then using that as the object to call the member function on. – Dave S Nov 20 '12 at 16:04
  • @DaveS missed the part with "invocation time". I thought that in case of member one had to do std::bind(&instance_member, objInstance, member_args..) – Ghita Nov 20 '12 at 17:29