// Copyright (C) 2019 T. Zachary Laine // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //[ reverse_iterator #include #include #include #include #include // In all the previous examples, we only had to implement a subset of the six // possible user-defined basis operations that was needed for one particular // iterator concept. For reverse_iterator, we want to support bidirectional, // random access, and contiguous iterators. We therefore need to provide all // the basis operations that might be needed. template struct reverse_iterator : boost::stl_interfaces::iterator_interface< reverse_iterator, #if 201703L < __cplusplus && defined(__cpp_lib_ranges) boost::stl_interfaces::v2::detail::iter_concept_t, #else typename std::iterator_traits::iterator_category, #endif typename std::iterator_traits::value_type> { reverse_iterator() : it_() {} reverse_iterator(BidiIter it) : it_(it) {} using ref_t = typename std::iterator_traits::reference; using diff_t = typename std::iterator_traits::difference_type; ref_t operator*() const { return *std::prev(it_); } // These three are used only when BidiIter::iterator_category is // std::bidirectional_iterator_tag. bool operator==(reverse_iterator other) const { return it_ == other.it_; } // Even though iterator_interface-derived bidirectional iterators are // usually given operator++() and operator--() members, it turns out that // operator+=() below amounts to the same thing. That's good, since // having operator++() and operator+=() in this class would have lead to // ambiguities in iterator_interface. // These two are only used when BidiIter::iterator_category is // std::random_access_iterator_tag or std::contiguous_iterator_tag. Even // so, they need to compile even when BidiIter::iterator_category is // std::bidirectional_iterator_tag. That means we have to use // std::distance() and std::advance() instead of operator-() and // operator+=(). // // Don't worry, the O(n) bidirectional implementations of std::distance() // and std::advance() are dead code, because compare() and advance() are // never even called when BidiIter::iterator_category is // std::bidirectional_iterator_tag. diff_t operator-(reverse_iterator other) const { return -std::distance(other.it_, it_); } reverse_iterator & operator+=(diff_t n) { std::advance(it_, -n); return *this; } // No need for a using declaration to make // iterator_interface::operator++(int) visible, because we're not defining // operator++() in this template. private: BidiIter it_; }; using rev_bidi_iter = reverse_iterator::iterator>; using rev_ra_iter = reverse_iterator::iterator>; int main() { { std::list ints = {4, 3, 2}; std::list ints_copy; std::copy( rev_bidi_iter(ints.end()), rev_bidi_iter(ints.begin()), std::back_inserter(ints_copy)); std::reverse(ints.begin(), ints.end()); assert(ints_copy == ints); } { std::vector ints = {4, 3, 2}; std::vector ints_copy(ints.size()); std::copy( rev_ra_iter(ints.end()), rev_ra_iter(ints.begin()), ints_copy.begin()); std::reverse(ints.begin(), ints.end()); assert(ints_copy == ints); } { using rev_ptr_iter = reverse_iterator; int ints[3] = {4, 3, 2}; int ints_copy[3]; std::copy( rev_ptr_iter(std::end(ints)), rev_ptr_iter(std::begin(ints)), std::begin(ints_copy)); std::reverse(std::begin(ints), std::end(ints)); assert(std::equal( std::begin(ints_copy), std::end(ints_copy), std::begin(ints), std::end(ints))); } } //]