Rikardo Koder
Rikardo Koder

Reputation: 672

Creating boost::thread with an std::shared_ptr object instance

I have the following two code segments. The first block compiles and works as expected. However the second block does not compile.

My question is, given the code below what is the correct syntax when trying to create a thread based on an instance of an object that is being proxied by a shared_ptr?

#include <iostream>
#include <new> 
#include <memory>

#include <boost/thread.hpp>

struct foo
{
   void boo() {}
};

int main()
{
   //This works
   {
      foo* fptr = new foo;
      boost::thread t(&foo::boo,fptr);
      t.join();
      delete fptr;
   }

   //This doesn't work
   {
      std::shared_ptr<foo> fptr(new foo);
      boost::thread t(&foo::boo,fptr);
      t.join();
   }

   return 0;
}

The compiler error:

Error   5   error C2784: 'T *boost::get_pointer(T *)' : could not deduce template argument for 'T *' from 'std::tr1::shared_ptr<_Ty>'   c:\program files (x86)\boost\boost_1_47\boost\bind\mem_fn_template.hpp  40  1   htest
Error   3   error C2784: 'T *boost::get_pointer(const std::auto_ptr<_Ty> &)' : could not deduce template argument for 'const std::auto_ptr<_Ty> &' from 'std::tr1::shared_ptr<_Ty>' c:\program files (x86)\boost\boost_1_47\boost\bind\mem_fn_template.hpp  40  1   htest
Error   4   error C2784: 'T *boost::get_pointer(const std::auto_ptr<_Ty> &)' : could not deduce template argument for 'const std::auto_ptr<_Ty> &' from 'std::tr1::shared_ptr<_Ty>' c:\program files (x86)\boost\boost_1_47\boost\bind\mem_fn_template.hpp  40  1   htest
Error   8   error C2784: 'T *boost::get_pointer(const boost::shared_ptr<X> &)' : could not deduce template argument for 'const boost::shared_ptr<X> &' from 'std::tr1::shared_ptr<_Ty>' c:\program files (x86)\boost\boost_1_47\boost\bind\mem_fn_template.hpp  40  1   htest
Error   9   error C2784: 'T *boost::get_pointer(const boost::shared_ptr<X> &)' : could not deduce template argument for 'const boost::shared_ptr<X> &' from 'std::tr1::shared_ptr<_Ty>' c:\program files (x86)\boost\boost_1_47\boost\bind\mem_fn_template.hpp  40  1   htest
Error   1   error C2784: 'T *boost::get_pointer(const boost::scoped_ptr<T> &)' : could not deduce template argument for 'const boost::scoped_ptr<T> &' from 'std::tr1::shared_ptr<_Ty>' c:\program files (x86)\boost\boost_1_47\boost\bind\mem_fn_template.hpp  40  1   htest
Error   2   error C2784: 'T *boost::get_pointer(const boost::scoped_ptr<T> &)' : could not deduce template argument for 'const boost::scoped_ptr<T> &' from 'std::tr1::shared_ptr<_Ty>' c:\program files (x86)\boost\boost_1_47\boost\bind\mem_fn_template.hpp  40  1   htest
Error   6   error C2784: 'T *boost::get_pointer(const boost::reference_wrapper<T> &)' : could not deduce template argument for 'const boost::reference_wrapper<T> &' from 'std::tr1::shared_ptr<_Ty>'   c:\program files (x86)\boost\boost_1_47\boost\bind\mem_fn_template.hpp  40  1   htest
Error   7   error C2784: 'T *boost::get_pointer(const boost::reference_wrapper<T> &)' : could not deduce template argument for 'const boost::reference_wrapper<T> &' from 'std::tr1::shared_ptr<_Ty>'   c:\program files (x86)\boost\boost_1_47\boost\bind\mem_fn_template.hpp  40  1   htest
Error   10  error C2784: 'T *boost::get_pointer(const boost::intrusive_ptr<T> &)' : could not deduce template argument for 'const boost::intrusive_ptr<T> &' from 'std::tr1::shared_ptr<_Ty>'   c:\program files (x86)\boost\boost_1_47\boost\bind\mem_fn_template.hpp  40  1   htest
Error   11  error C2784: 'T *boost::get_pointer(const boost::intrusive_ptr<T> &)' : could not deduce template argument for 'const boost::intrusive_ptr<T> &' from 'std::tr1::shared_ptr<_Ty>'   c:\program files (x86)\boost\boost_1_47\boost\bind\mem_fn_template.hpp  40  1   htest

Upvotes: 5

Views: 3252

Answers (2)

Jonathan Wakely
Jonathan Wakely

Reputation: 171443

An alternative to Dave S's answer is to define this (before <boost/mem_fn.hpp> gets included):

namespace boost
{
  template<typename T>
    inline T*
    get_pointer(const std::shared_ptr<T>& p)
    { return p.get(); }
}

That "teaches" boost::mem_fn to obtain a raw pointer from a std::shared_ptr.

In C++11 std::mem_fn is required to work with any pointer-like type, simply by dereferencing it i.e. *fptr, but boost::mem_fn instead uses *boost::get_pointer(fptr). I don't know if it's fixed in the latest version of Boost, but I would argue that it should use SFINAE to detect whether get_pointer will work, and should just dereference it otherwise.

Upvotes: 3

Dave S
Dave S

Reputation: 21123

The problem is that boost::thread relies on boost::mem_fn to handle member functions, and boost::mem_fn (or at least the version you are using) doesn't know how to use a std::shared_ptr to invoke a member function as it expects you to use boost::shared_ptr or one of the myriad of other smart pointer types in your error listing.

The raw pointer works because boost::mem_fn already has that overload. The solutions are to use boost::shared_ptr or std::mem_fn. The latter works because std::mem_fn knows how to interact with std::shared_ptr

boost::thread t(std::mem_fn(&foo::boo), fptr);

Upvotes: 9

Related Questions