The reverse iterator adaptor flips the direction of a base iterator's motion. Invoking operator++() moves the base iterator backward and invoking operator--() moves the base iterator forward. The Boost reverse iterator adaptor is better to use than the std::reverse_iterator class in situations where pairs of mutable/constant iterators are needed (e.g., in containers) because comparisons and conversions between the mutable and const versions are implemented correctly.
namespace boost { template <class BidirectionalIterator, class Value, class Reference, class Pointer, class Category, class Distance> struct reverse_iterator_generator; template <class BidirectionalIterator> typename reverse_iterator_generator<BidirectionalIterator>::type make_reverse_iterator(BidirectionalIterator base) }
template <class BidirectionalIterator, class Value, class Reference, class Pointer, class Category, class Distance> class reverse_iterator_generator { public: typedef iterator_adaptor<...> type; // the resulting reverse iterator type };
The output is:#include <boost/config.hpp> #include <iostream> #include <algorithm> #include <boost/iterator_adaptors.hpp> int main(int, char*[]) { char letters[] = "hello world!"; const int N = sizeof(letters)/sizeof(char) - 1; std::cout << "original sequence of letters:\t" << letters << std::endl; std::sort(letters, letters + N); // Use reverse_iterator_generator to print a sequence // of letters in reverse order. boost::reverse_iterator_generator<char*>::type reverse_letters_first(letters + N), reverse_letters_last(letters); std::cout << "letters in descending order:\t"; std::copy(reverse_letters_first, reverse_letters_last, std::ostream_iterator<char>(std::cout)); std::cout << std::endl; // to be continued...
original sequence of letters: hello world! letters in descending order: wroolllhed!
Parameter | Description |
---|---|
BidirectionalIterator | The iterator type being wrapped. |
Value | The value-type of the base iterator and the resulting reverse
iterator. Default:std::iterator_traits<BidirectionalIterator>::value_type |
Reference | The reference type of the resulting iterator, and in
particular, the result type of operator*(). Default: If Value is supplied, Value& is used. Otherwise std::iterator_traits<BidirectionalIterator>::reference is used. |
Pointer | The pointer type of the resulting iterator, and in
particular, the result type of operator->(). Default: If Value was supplied, then Value*, otherwise std::iterator_traits<BidirectionalIterator>::pointer. |
Category | The iterator_category type for the resulting iterator. Default: std::iterator_traits<BidirectionalIterator>::iterator_category |
Distance | The difference_type for the resulting iterator. Default: std::iterator_traits<BidirectionalIterator>::difference_type |
reverse_iterator_generator::type(const BidirectionalIterator& it)
template <class BidirectionalIterator> typename reverse_iterator_generator<BidirectionalIterator>::type make_reverse_iterator(BidirectionalIterator base);
The output is:// continuing from the previous example... std::cout << "letters in ascending order:\t"; std::copy(boost::make_reverse_iterator(reverse_letters_last), boost::make_reverse_iterator(reverse_letters_first), std::ostream_iterator<char>(std::cout)); std::cout << std::endl; return 0; }
letters in ascending order: !dehllloorw
One failing of the standard reverse_iterator adaptor is that it doesn't properly support interactions between adapted const and non-const iterators. For example:
Reverse iterators created with boost::reverse_iterator_generator don't have this problem, though:#include <vector> template <class T> void convert(T x) {} // Test interactions of a matched pair of random access iterators template <class Iterator, class ConstIterator> void test_interactions(Iterator i, ConstIterator ci) { bool eq = i == ci; // comparisons bool ne = i != ci; bool lt = i < ci; bool le = i <= ci; bool gt = i > ci; bool ge = i >= ci; std::size_t distance = i - ci; // difference ci = i; // assignment ConstIterator ci2(i); // construction convert<ConstIterator>(i); // implicit conversion } void f() { typedef std::vector<int> vec; vec v; const vec& cv; test_interactions(v.begin(), cv.begin()); // OK test_interactions(v.rbegin(), cv.rbegin()); // ERRORS ON EVERY TEST!!
Or, more simply,typedef boost::reverse_iterator_generator<vec::iterator>::type ri; typedef boost::reverse_iterator_generator<vec::const_iterator>::type cri; test_interactions(ri(v.begin()), cri(cv.begin())); // OK!!
test_interactions( boost::make_reverse_iterator(v.begin()), boost::make_reverse_iterator(cv.begin())); // OK!! }
If you are wondering why there is no
reverse_iterator_pair_generator in the manner of projection_iterator_pair_generator,
the answer is simple: we tried it, but found that in practice it took
more typing to use reverse_iterator_pair_generator than to
simply use reverse_iterator_generator twice!
Revised 17 Aug 2001
© Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.