简体   繁体   中英

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.

You can usually tell the compiler which overload you want by specifying the type of the function pointer you want eg

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 eg

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM