Now your BaseClassB<T>::begin and end returns an any_iterator<T>. Things that match the concept, including DerivedClassA<T>, can be stored and manipulated within it. BaseClassA<T> becomes obsolete, as a type erasing iterator does not require a virtual base class for polymorphism.

DerivedClassB<T> also returns an any_iterator<T>. If you want naked access to the real iterators of DerivedClassB<T> have a function called get_naked_range() that returns the naked iterators of DerivedClassB<T>, which can be used in contexts where you are absolutely certain the type is DerivedClassB<T>. If you do so, also mark begin and end as final.

Note that such type erasure has runtime costs, and iterating through it will be slower than "raw naked" iteration. This only matters if you are doing this at a pretty low level in a high performance context, don't let it scare you away.