Search code examples
c++booststlshared-ptrboost-bind

Transform vector of boost::shared_ptr using boost::bind and boost::static_pointer_cast


I have a std::vector of Boost shared pointers to objects, and would like to get a vector of shared pointers to the same objects casted down to a more specific type:

//using boost::shared_ptr, std::vector;
vector<shared_ptr<A> > originalVec;
vector<shared_ptr<B> > targetVec( originalVec.size() ); // B extends A

For a single element shared_ptr<A> elem, it is possible to cast it using boost::static_pointer_cast<B>(elem), whose syntax is reproduced below (from Boost shared_ptr doc):

template<class T, class U>
shared_ptr<T> static_pointer_cast(shared_ptr<U> const & r); // never throws

I don't know how to use it with std::transform. Mi tries include:

//using boost::bind, boost::static_pointer_cast
transform( originalVec.begin(), originalVec.end(), targetVec.begin(), bind( static_pointer_cast<B>, _1) )
transform( originalVec.begin(), originalVec.end(), targetVec.begin(), bind( static_pointer_cast<B,A>, _1) ) 

Getting in both cases a "no matching function for call to bind(<unresolved overloaded function type>, boost::arg<1>& )"

Any ideas?


EDIT: The problem could be related with an ambiguity, since a similar function template is defined for intrusive pointer class, with syntax:

template<class T, class U>
intrusive_ptr<T> static_pointer_cast(intrusive_ptr<U> const & r); // never throws

The question, in this case, is how to specify the type of the first argument so that the compiler knows which method to select.


Solution

  • You can usually tell the compiler which overload you want by specifying the type of the function pointer you want e.g.

    typedef shared_ptr<B>(*func_type)(const shared_ptr<A>&);
    
    transform( originalVec.begin(), originalVec.end(), targetVec.begin(), bind( (func_type)static_pointer_cast<B,A>, _1) );
    

    But in cases where you get this sort of error from an overloaded function that can't be disambiguated, my preferred solution is often to provide a custom functor that does the call, so that overload resolution is done by the compiler, and you don't have to select an overload e.g.

    struct Downcast {
      shared_ptr<B> operator()(const shared_ptr<A>& p) const
      { return shared_pointer_cast<B>(p); }
    };
    
    transform( originalVec.begin(), originalVec.end(), targetVec.begin(), Downcast() );