简体   繁体   中英

How to convert unique_ptr<derived>* to unique_ptr<base>*?

I've got 4 classes, base , base_collection and derived::base , derived_collection::base_collection ;

In base_collection there is a constructor with signature:

base_collection(unique_ptr<base> *begin, unique_ptr<base> *end)

In derived_collection there is a constructor with signature:

derived_collection (unique_ptr<derived> *begin, unique_ptr<derived> *end)

And obviously I want to implement it as

derived_collection (unique_ptr<derived> *begin, unique_ptr<derived> *end) :
  base_collection(something(begin), something(end)) {}

But I'm struggling with the something . I guess its a custom iterator, but my attempts so far have failed as it keeps telling me that my custom iterator isn't convertible to unique_ptr<base> *begin . I'm not really bothered at this point as to whether what I'm doing is a good idea or not, I'm just keen to know how to get this working.

I'm using C++17.

EDIT

To give some context unique_ptr<base> *base is an iterator, not necessarily a pointer. The base_collection constructor iterates from begin to end .

What I want to do is iterate over a derived collection via begin / end iterators that the compiler sees as base iterators.

something is exactly that. I'm not sure what needs to be done to begin and end to make the compiler happy.

UPDATE

Alas someone who hadn't read the comments or didn't understand them decided to hide them all, however it seems like what I was attempting to do was either impossible or close to impossible and the conclusion was that a different approach was needed.

std::unique_ptr<Base>* cannot be converted std::unique_ptr<Derived>* because they are unrelated classes, even though template argument Derived derives from Base publicly.

To solve your problem, you need another level of indirection. Eg, a special iterator type that double-dereferences unique_ptr<Base>* and down-casts Base& to Derived& in Iter::operator* and Iter::operator[] , and Base* to Derived* in Iter::operator-> . You can create such an iterator from scratch, but that's a lot of boiler-plate code typing, or use boost::iterator_facade that implements that boiler-plate code for you.

So, you'd have Iter<Base, unique_ptr<Base>*> and Iter<Derived, unique_ptr<Base>*> and they must be convertible to each other, as long as the second template arguments match. And then:

base_collection(Iter<Base, unique_ptr<Base>*> begin, Iter<Base, unique_ptr<Base>*> end);

derived_collection(Iter<Derived, unique_ptr<Base>*> begin, Iter<Derived, unique_ptr<Base>*> end) :
  base_collection(begin, end) {} // Implicit conversion Iter<Derived, unique_ptr<Base>*> -> Iter<Base, unique_ptr<Base>*>.

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