Const casting container value-types seems not possible. A comment in the other question suggests iterators as a solution, yet does not go into detail. Since I seemingly cannot simply convert a container from a non-const to a const version as a function parameter, I arrive at Iterators to maybe be able to do the job.
I actually have a vector<shared_ptr<Thing> > to be treated as const vector<shared_ptr<Thing const> >.
With it I intend to use the shared_ptr<Thing const> as further references in other structures, without allowing those structures to alter the Things. Those structures may create their own objects, stored by their own shared_ptr, if they want slightly different content within their containers, while still actively sharing most Things with other objects.
So I would need either shared_ptr<const Thing>&, or const shared_ptr<const Thing>& from an Iterator through the sequence. Either would suffice, but just because one can be indifferent about passing references in this example, because of shared_ptr's copy semantics are about just that.
Yet even just using default const_iterator, retrieved by cbegin(),c.end() and such, will give me a const shared_ptr<Thing>& instead.
Edit: To copy the vector element for element would be one way technically, as in the other question, yet undesired for interface reasons. I am going for reinterpretation here, not copy.
Any suggestions on where a workaround might lie?
Based on your situation, it sounds like defining a custom iterator with the semantics you want is the safe and simple way to go. It's technically correct, hard to accidentally misuse, and fairly fast, just requiring a
shared_ptrcopy on iterator dereference.I always recommend
boost::iterator_facadeorboost::iterator_adaptorfor creating an iterator type. Since it will contain the originalvectoriterator as a "base" implementation,iterator_adaptoris helpful.The
referenceiterator type would bestd::shared_ptr<const Thing>&by default, but in this case it can't be a reference since there is no object of that type. Normally the class would define some of the behavior functions likedereferenceorincrement, but none are needed here: the only change from the base vector iterator is to the return type ofoperator*, and the defaultreference dereference() const { return *base_reference(); }works fine by implicit conversion fromconst std::shared_ptr<Thing>&tostd::shared_ptr<const Thing>.The class could also be a template taking
Thingas its type parameter, to create multiple iterator types.Then to provide a container-like view object, we can use C++20's
std::ranges::subrangeto providebegin()andend()and a few other things helping the out the range templates:Or if that's not available, a simple class with
begin()andend():Demo on godbolt. (Clang doesn't like the ranges code due to this libstdc++ incompatibility; I'm not sure how to get godbolt to switch it to clang's libc++.)