Question

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.

Was it helpful?

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() );

OTHER TIPS

I'm not sure why you got that error with your second try, because that one should've worked.

However, there is a possibility you'll overrun the bounds of targetVec if it is empty because simply passing an iterator to transform is not enough, you need to push_back the result of the cast into targetVec. This can be done easily by passing a back_insert_iterator to transform.

int main()
{
    std::vector<boost::shared_ptr<A>> original;
    std::vector<boost::shared_ptr<B>> target;

    original.push_back( boost::make_shared<B>() );

    boost::transform( original,
                      std::back_inserter( target ),
                      boost::bind( boost::static_pointer_cast<B, A>, _1 ) );

    // OR
    std::transform( original.begin(), 
                    original.end(),
                    std::back_inserter( target ),
                    boost::bind( boost::static_pointer_cast<B, A>, _1 ) );
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top