Reputation: 9861
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.
Upvotes: 0
Views: 121
Reputation: 136286
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. E.g., 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>*>.
Upvotes: 1