I have a class which contains and manages a series of objects. To avoid leaking how these objects are stored while allowing to iterate through them, I decided to use type erasure using boost::any_iterator
.
using my_erased_type_iterator = boost::range_detail::any_iterator<
MyClass,
boost::bidirectional_traversal_tag,
MyClass&,
std::ptrdiff_t>;
I defined a function Begin()
and End()
in MyClass
, which simply returns the container's begin()
and end()
function as a my_erased_type_iterator
. It works exactly as I want to, and nobody outside of MyClass
knows I'm using a vector to store the objects nor do they have access to the container aside from the functions I expose in Myclass
's interface.
Now, for a number of reasons, I need to reverse-iterate through the objects. I also need to know the next element after a reverse iterator (akin to calling std::next()
on a normal iterator, which is already not so trivial for reverse iterators) and I might also need to call functions like erase()
on that reverse iterator.
So for my question: is there an elegant way to use type-erasure along with reverse iterators (and the const version of both forward and reverse) ? Should I use forward type-erased iterators and iterate backward instead? It crossed my mind that I might be tackling this problem the wrong way, so I'm open to any suggestions or to clarify my questions if needed.
Note that any_iterator
is an implementation detail.
I'll answer your direct question first, then show the approach with any_range<>
as intended by the public API of Boost Range.
make_reverse_iterator
You can simply use the make_reverse_iterator
facility from
#include <boost/range.hpp>
#include <boost/range/any_range.hpp>
struct MyClass {
int i;
};
using my_erased_type_iterator = boost::range_detail::any_iterator<
MyClass,
boost::bidirectional_traversal_tag,
MyClass&,
std::ptrdiff_t>;
#include <iostream>
#include <vector>
int main() {
using namespace boost;
std::vector<MyClass> const v { {1}, {2}, {3}, {4} };
for (auto& mc : make_iterator_range(
make_reverse_iterator(v.end()),
make_reverse_iterator(v.begin())))
{
std::cout << mc.i << " ";
}
}
Prints
4 3 2 1
reversed
range adaptor:Alternatively, you can go full range-style and use any_range<>
:
int main() {
std::vector<MyClass> const v { {1}, {2}, {3}, {4} };
boost::any_range_type_generator<decltype(v)>::type x = reverse(v);
for (my_erased_type_const_iterator f = boost::begin(x), l = boost::end(x); f!=l; ++f) {
std::cout << f->i << " ";
}
}