Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/iterator/reverse iterator"

From cppreference.com
< cpp‎ | iterator
m (Example: "Stack" size: 4 -> 8 to show that it may not be "full" to be traversable (h'm). It's a pity std::stack doesn't have begin/end (at least constexpr-conditionally)...)
(New iterator concepts relax the requirements)
Line 109: Line 109:
  
 
===Notes===
 
===Notes===
{{tt|std::reverse_iterator}} does not work with iterators whose dereference returns a reference to a member of {{tt|*this}} (so-called "stashing iterators"). An example of a stashing iterator is {{ltt|cpp/filesystem/path#Member_types_and_constants|std::filesystem::path::iterator}}.
+
{{rrev|until=c++20|{{tt|std::reverse_iterator}} does not work with iterators whose dereference returns a reference to a member of {{tt|*this}} (so-called "stashing iterators"). An example of a stashing iterator is {{ltt|cpp/filesystem/path#Member_types_and_constants|std::filesystem::path::iterator}}.}}
  
 
===Example===
 
===Example===

Revision as of 01:57, 20 July 2021

 
 
Iterator library
Iterator concepts
Iterator primitives
Algorithm concepts and utilities
Indirect callable concepts
Common algorithm requirements
(C++20)
(C++20)
(C++20)
Utilities
(C++20)
Iterator adaptors
Range access
(C++11)(C++14)
(C++14)(C++14)  
(C++11)(C++14)
(C++14)(C++14)  
(C++17)(C++20)
(C++17)
(C++17)
 
 
Defined in header <iterator>
template< class Iter >
class reverse_iterator;

std::reverse_iterator is an iterator adaptor that reverses the direction of a given iterator, which must be at least a LegacyBidirectionalIterator or model bidirectional_iterator(since C++20). In other words, when provided with a bidirectional iterator, std::reverse_iterator produces a new iterator that moves from the end to the beginning of the sequence defined by the underlying bidirectional iterator.

For a reverse iterator r constructed from an iterator i, the relationship &*r == &*(i-1) is always true (as long as r is dereferenceable); thus a reverse iterator constructed from a one-past-the-end iterator dereferences to the last element in a sequence.

This is the iterator returned by member functions rbegin() and rend() of the standard library containers.

range-rbegin-rend.svg

Contents

Member types

Member type Definition
iterator_type Iter
iterator_category std::iterator_traits<Iter>::iterator_category
value_type std::iterator_traits<Iter>::value_type
difference_type std::iterator_traits<Iter>::difference_type
pointer std::iterator_traits<Iter>::pointer
reference std::iterator_traits<Iter>::reference
(until C++20)
Member type Definition
iterator_type Iter
iterator_concept If Iter models std::random_access_iterator, this is std::random_access_iterator_tag. Otherwise, this is std::bidirectional_iterator_tag
iterator_category If std::iterator_traits<Iter>::iterator_category models std::derived_from<std::random_access_iterator_tag>, this is std::random_access_iterator_tag. Otherwise, this is std::iterator_traits<Iter>::iterator_category
value_type std::iter_value_t<Iter>
difference_type std::iter_difference_t<Iter>
pointer std::iterator_traits<Iter>::pointer
reference std::iter_reference_t<Iter>
(since C++20)

Member types iterator_category, value_type, difference_type, pointer and reference are required to be obtained by inheriting from std::iterator<
  std::iterator_traits<Iter>::iterator_category
, std::iterator_traits<Iter>::value_type
, std::iterator_traits<Iter>::difference_type
, std::iterator_traits<Iter>::pointer
, std::iterator_traits<Iter>::reference
>
.

(until C++17)

Member functions

constructs a new iterator adaptor
(public member function) [edit]
assigns another iterator adaptor
(public member function) [edit]
accesses the underlying iterator
(public member function) [edit]
accesses the pointed-to element
(public member function) [edit]
accesses an element by index
(public member function) [edit]
advances or decrements the iterator
(public member function) [edit]

Member objects

Member name Definition
current (protected) the underlying iterator of which base() returns a copy

Non-member functions

compares the underlying iterators
(function template) [edit]
advances the iterator
(function template) [edit]
computes the distance between two iterator adaptors
(function template) [edit]
(C++20)
casts the result of dereferencing the adjusted underlying iterator to its associated rvalue reference type
(function) [edit]
(C++20)
swaps the objects pointed to by two adjusted underlying iterators
(function template) [edit]
creates a std::reverse_iterator of type inferred from the argument
(function template) [edit]

Helper templates

template< class Iterator1, class Iterator2 >

    requires (!std::sized_sentinal_for<Iterator1, Iterator2>)
inline constexpr bool disable_sized_sentinel_for<
    std::reverse_iterator<Iterator1>,

    std::reverse_iterator<Iterator2>> = true;
(since C++20)

This partial specialization of std::disable_sentinel_for prevents specializations of reverse_iterator from satisfying sized_sentinel_for if their underlying iterators do not satisfy the concept.

Possible implementation

Below is a partial implementation focusing on the way the inner iterator is saved, calling prev only when the content is fetched via operator*.

template<typename Itr>
class reverse_iterator {
    Itr itr;
public:
    constexpr explicit reverse_iterator(Itr itr): itr(itr) {}
    constexpr auto& operator*() {
        return *std::prev(itr); // <== returns the content of prev
    }
    constexpr auto& operator++() {
        --itr;
        return *this;
    }
    constexpr friend bool operator!=(reverse_iterator<Itr> a, reverse_iterator<Itr> b) {
        return a.itr != b.itr;
    }
};

Notes

std::reverse_iterator does not work with iterators whose dereference returns a reference to a member of *this (so-called "stashing iterators"). An example of a stashing iterator is std::filesystem::path::iterator.

(until C++20)

Example

#include <iostream>
#include <iterator>
 
template<typename T, size_t SIZE>
class Stack {
    T arr[SIZE];
    size_t pos = 0;
public:
    T pop() {
        return arr[--pos];
    }
    Stack& push(const T& t) {
        arr[pos++] = t;
        return *this;
    }
    // we wish that looping on Stack would be in LIFO order
    // thus we use std::reverse_iterator as an adaptor to existing iterators
    // (which are in this case the simple pointers: [arr, arr+pos)
    auto begin() {
        return std::reverse_iterator(arr + pos);
    }
    auto end() {
        return std::reverse_iterator(arr);
    }
};
 
int main() {
    Stack<int, 8> s;
    s.push(5).push(15).push(25).push(35);
    for(int val: s) {
        std::cout << val << ' ';
    }
}

Output:

35 25 15 5

See also

creates a std::reverse_iterator of type inferred from the argument
(function template) [edit]
(deprecated in C++17)
base class to ease the definition of required types for simple iterators
(class template) [edit]