23 Iterators library [iterators]

23.5 Iterator adaptors [predef.iterators]

23.5.1 Reverse iterators [reverse.iterators]

Class template reverse_­iterator is an iterator adaptor that iterates from the end of the sequence defined by its underlying iterator to the beginning of that sequence.

23.5.1.1 Class template reverse_­iterator [reverse.iterator]

namespace std {
  template<class Iterator>
  class reverse_iterator {
  public:
    using iterator_type     = Iterator;
    using iterator_concept  = see below;
    using iterator_category = see below;
    using value_type        = iter_value_t<Iterator>;
    using difference_type   = iter_difference_t<Iterator>;
    using pointer           = typename iterator_traits<Iterator>::pointer;
    using reference         = iter_reference_t<Iterator>;

    constexpr reverse_iterator();
    constexpr explicit reverse_iterator(Iterator x);
    template<class U> constexpr reverse_iterator(const reverse_iterator<U>& u);
    template<class U> constexpr reverse_iterator& operator=(const reverse_iterator<U>& u);

    constexpr Iterator base() const;
    constexpr reference operator*() const;
    constexpr pointer   operator->() const requires see below;

    constexpr reverse_iterator& operator++();
    constexpr reverse_iterator  operator++(int);
    constexpr reverse_iterator& operator--();
    constexpr reverse_iterator  operator--(int);

    constexpr reverse_iterator  operator+ (difference_type n) const;
    constexpr reverse_iterator& operator+=(difference_type n);
    constexpr reverse_iterator  operator- (difference_type n) const;
    constexpr reverse_iterator& operator-=(difference_type n);
    constexpr unspecified operator[](difference_type n) const;

    friend constexpr iter_rvalue_reference_t<Iterator>
      iter_move(const reverse_iterator& i) noexcept(see below);
    template<indirectly_swappable<Iterator> Iterator2>
      friend constexpr void
        iter_swap(const reverse_iterator& x,
                  const reverse_iterator<Iterator2>& y) noexcept(see below);

  protected:
    Iterator current;
  };
}
The member typedef-name iterator_­concept denotes
  • random_­access_­iterator_­tag if Iterator models random_­access_­iterator, and
  • bidirectional_­iterator_­tag otherwise.
The member typedef-name iterator_­category denotes
  • random_­access_­iterator_­tag if the type iterator_­traits<​Iterator>​::​iterator_­category models derived_­from<random_­access_­iterator_­tag>, and
  • iterator_­traits<​Iterator>​::​iterator_­category otherwise.

23.5.1.2 Requirements [reverse.iter.requirements]

The template parameter Iterator shall either meet the requirements of a Cpp17BidirectionalIterator ([bidirectional.iterators]) or model bidirectional_­iterator ([iterator.concept.bidir]).
Additionally, Iterator shall either meet the requirements of a Cpp17RandomAccessIterator ([random.access.iterators]) or model random_­access_­iterator ([iterator.concept.random.access]) if the definitions of any of the members or the non-member operators ([reverse.iter.cmp]) are instantiated ([temp.inst]).

23.5.1.3 Construction and assignment [reverse.iter.cons]

constexpr reverse_iterator();
Effects: Value-initializes current.
Iterator operations applied to the resulting iterator have defined behavior if and only if the corresponding operations are defined on a value-initialized iterator of type Iterator.
constexpr explicit reverse_iterator(Iterator x);
Effects: Initializes current with x.
template<class U> constexpr reverse_iterator(const reverse_iterator<U>& u);
Effects: Initializes current with u.current.
template<class U> constexpr reverse_iterator& operator=(const reverse_iterator<U>& u);
Effects: Assigns u.base() to current.
Returns: *this.

23.5.1.4 Conversion [reverse.iter.conv]

constexpr Iterator base() const; // explicit
Returns: current.

23.5.1.5 Element access [reverse.iter.elem]

constexpr reference operator*() const;
Effects: As if by:
Iterator tmp = current;
return *--tmp;
constexpr pointer operator->() const requires (is_pointer_v<Iterator> || requires (const Iterator i) { i.operator->(); });
Effects:
  • If Iterator is a pointer type, equivalent to: return prev(current);
  • Otherwise, equivalent to: return prev(current).operator->();
constexpr unspecified operator[](difference_type n) const;
Returns: current[-n-1].

23.5.1.6 Navigation [reverse.iter.nav]

constexpr reverse_iterator operator+(difference_type n) const;
Returns: reverse_­iterator(current-n).
constexpr reverse_iterator operator-(difference_type n) const;
Returns: reverse_­iterator(current+n).
constexpr reverse_iterator& operator++();
Effects: As if by: --current;
Returns: *this.
constexpr reverse_iterator operator++(int);
Effects: As if by:
reverse_iterator tmp = *this;
--current;
return tmp;
constexpr reverse_iterator& operator--();
Effects: As if by ++current.
Returns: *this.
constexpr reverse_iterator operator--(int);
Effects: As if by:
reverse_iterator tmp = *this;
++current;
return tmp;
constexpr reverse_iterator& operator+=(difference_type n);
Effects: As if by: current -= n;
Returns: *this.
constexpr reverse_iterator& operator-=(difference_type n);
Effects: As if by: current += n;
Returns: *this.

23.5.1.7 Comparisons [reverse.iter.cmp]

template<class Iterator1, class Iterator2> constexpr bool operator==( const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
Constraints: x.base() == y.base() is well-formed and convertible to bool.
Returns: x.base() == y.base().
template<class Iterator1, class Iterator2> constexpr bool operator!=( const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
Constraints: x.base() != y.base() is well-formed and convertible to bool.
Returns: x.base() != y.base().
template<class Iterator1, class Iterator2> constexpr bool operator<( const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
Constraints: x.base() > y.base() is well-formed and convertible to bool.
Returns: x.base() > y.base().
template<class Iterator1, class Iterator2> constexpr bool operator>( const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
Constraints: x.base() < y.base() is well-formed and convertible to bool.
Returns: x.base() < y.base().
template<class Iterator1, class Iterator2> constexpr bool operator<=( const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
Constraints: x.base() >= y.base() is well-formed and convertible to bool.
Returns: x.base() >= y.base().
template<class Iterator1, class Iterator2> constexpr bool operator>=( const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
Constraints: x.base() <= y.base() is well-formed and convertible to bool.
Returns: x.base() <= y.base().
template<class Iterator1, three_­way_­comparable_­with<Iterator1> Iterator2> constexpr compare_three_way_result_t<Iterator1, Iterator2> operator<=>(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
Returns: y.base() <=> x.base().
[Note
:
The argument order in the Returns: element is reversed because this is a reverse iterator.
β€” end note
]

23.5.1.8 Non-member functions [reverse.iter.nonmember]

template<class Iterator1, class Iterator2> constexpr auto operator-( const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y) -> decltype(y.base() - x.base());
Returns: y.base() - x.base().
template<class Iterator> constexpr reverse_iterator<Iterator> operator+( iter_difference_t<Iterator> n, const reverse_iterator<Iterator>& x);
Returns: reverse_­iterator<Iterator>(x.base() - n).
friend constexpr iter_rvalue_reference_t<Iterator> iter_move(const reverse_iterator& i) noexcept(see below);
Effects: Equivalent to:
auto tmp = i.base();
return ranges::iter_move(--tmp);
Remarks: The expression in noexcept is equivalent to:
is_nothrow_copy_constructible_v<Iterator> &&
noexcept(ranges::iter_move(--declval<Iterator&>()))
template<indirectly_­swappable<Iterator> Iterator2> friend constexpr void iter_swap(const reverse_iterator& x, const reverse_iterator<Iterator2>& y) noexcept(see below);
Effects: Equivalent to:
auto xtmp = x.base();
auto ytmp = y.base();
ranges::iter_swap(--xtmp, --ytmp);
Remarks: The expression in noexcept is equivalent to:
is_nothrow_copy_constructible_v<Iterator> &&
is_nothrow_copy_constructible_v<Iterator2> &&
noexcept(ranges::iter_swap(--declval<Iterator&>(), --declval<Iterator2&>()))
template<class Iterator> constexpr reverse_iterator<Iterator> make_reverse_iterator(Iterator i);
Returns: reverse_­iterator<Iterator>(i).

23.5.2 Insert iterators [insert.iterators]

To make it possible to deal with insertion in the same way as writing into an array, a special kind of iterator adaptors, called insert iterators, are provided in the library.
With regular iterator classes,
while (first != last) *result++ = *first++;
causes a range [first, last) to be copied into a range starting with result.
The same code with result being an insert iterator will insert corresponding elements into the container.
This device allows all of the copying algorithms in the library to work in the insert mode instead of the regular overwrite mode.
An insert iterator is constructed from a container and possibly one of its iterators pointing to where insertion takes place if it is neither at the beginning nor at the end of the container.
Insert iterators meet the requirements of output iterators.
operator* returns the insert iterator itself.
The assignment operator=(const T& x) is defined on insert iterators to allow writing into them, it inserts x right before where the insert iterator is pointing.
In other words, an insert iterator is like a cursor pointing into the container where the insertion takes place.
back_­insert_­iterator inserts elements at the end of a container, front_­insert_­iterator inserts elements at the beginning of a container, and insert_­iterator inserts elements where the iterator points to in a container.
back_­inserter, front_­inserter, and inserter are three functions making the insert iterators out of a container.

23.5.2.1 Class template back_­insert_­iterator [back.insert.iterator]

namespace std {
  template<class Container>
  class back_insert_iterator {
  protected:
    Container* container = nullptr;

  public:
    using iterator_category = output_iterator_tag;
    using value_type        = void;
    using difference_type   = ptrdiff_t;
    using pointer           = void;
    using reference         = void;
    using container_type    = Container;

    constexpr back_insert_iterator() noexcept = default;
    constexpr explicit back_insert_iterator(Container& x);
    constexpr back_insert_iterator& operator=(const typename Container::value_type& value);
    constexpr back_insert_iterator& operator=(typename Container::value_type&& value);

    constexpr back_insert_iterator& operator*();
    constexpr back_insert_iterator& operator++();
    constexpr back_insert_iterator  operator++(int);
  };
}

23.5.2.1.1 Operations [back.insert.iter.ops]

constexpr explicit back_insert_iterator(Container& x);
Effects: Initializes container with addressof(x).
constexpr back_insert_iterator& operator=(const typename Container::value_type& value);
Effects: As if by: container->push_­back(value);
Returns: *this.
constexpr back_insert_iterator& operator=(typename Container::value_type&& value);
Effects: As if by: container->push_­back(std​::​move(value));
Returns: *this.
constexpr back_insert_iterator& operator*();
Returns: *this.
constexpr back_insert_iterator& operator++(); constexpr back_insert_iterator operator++(int);
Returns: *this.

23.5.2.1.2 back_­inserter [back.inserter]

template<class Container> constexpr back_insert_iterator<Container> back_inserter(Container& x);
Returns: back_­insert_­iterator<Container>(x).

23.5.2.2 Class template front_­insert_­iterator [front.insert.iterator]

namespace std {
  template<class Container>
  class front_insert_iterator {
  protected:
    Container* container = nullptr;

  public:
    using iterator_category = output_iterator_tag;
    using value_type        = void;
    using difference_type   = ptrdiff_t;
    using pointer           = void;
    using reference         = void;
    using container_type    = Container;

    constexpr front_insert_iterator() noexcept = default;
    constexpr explicit front_insert_iterator(Container& x);
    constexpr front_insert_iterator& operator=(const typename Container::value_type& value);
    constexpr front_insert_iterator& operator=(typename Container::value_type&& value);

    constexpr front_insert_iterator& operator*();
    constexpr front_insert_iterator& operator++();
    constexpr front_insert_iterator  operator++(int);
  };
}

23.5.2.2.1 Operations [front.insert.iter.ops]

constexpr explicit front_insert_iterator(Container& x);
Effects: Initializes container with addressof(x).
constexpr front_insert_iterator& operator=(const typename Container::value_type& value);
Effects: As if by: container->push_­front(value);
Returns: *this.
constexpr front_insert_iterator& operator=(typename Container::value_type&& value);
Effects: As if by: container->push_­front(std​::​move(value));
Returns: *this.
constexpr front_insert_iterator& operator*();
Returns: *this.
constexpr front_insert_iterator& operator++(); constexpr front_insert_iterator operator++(int);
Returns: *this.

23.5.2.2.2 front_­inserter [front.inserter]

template<class Container> constexpr front_insert_iterator<Container> front_inserter(Container& x);
Returns: front_­insert_­iterator<Container>(x).

23.5.2.3 Class template insert_­iterator [insert.iterator]

namespace std {
  template<class Container>
  class insert_iterator {
  protected:
    Container* container = nullptr;
    ranges::iterator_t<Container> iter = ranges::iterator_t<Container>();

  public:
    using iterator_category = output_iterator_tag;
    using value_type        = void;
    using difference_type   = ptrdiff_t;
    using pointer           = void;
    using reference         = void;
    using container_type    = Container;

    insert_iterator() = default;
    constexpr insert_iterator(Container& x, ranges::iterator_t<Container> i);
    constexpr insert_iterator& operator=(const typename Container::value_type& value);
    constexpr insert_iterator& operator=(typename Container::value_type&& value);

    constexpr insert_iterator& operator*();
    constexpr insert_iterator& operator++();
    constexpr insert_iterator& operator++(int);
  };
}

23.5.2.3.1 Operations [insert.iter.ops]

constexpr insert_iterator(Container& x, ranges::iterator_t<Container> i);
Effects: Initializes container with addressof(x) and iter with i.
constexpr insert_iterator& operator=(const typename Container::value_type& value);
Effects: As if by:
iter = container->insert(iter, value);
++iter;
Returns: *this.
constexpr insert_iterator& operator=(typename Container::value_type&& value);
Effects: As if by:
iter = container->insert(iter, std::move(value));
++iter;
Returns: *this.
constexpr insert_iterator& operator*();
Returns: *this.
constexpr insert_iterator& operator++(); constexpr insert_iterator& operator++(int);
Returns: *this.

23.5.2.3.2 inserter [inserter]

template<class Container> constexpr insert_iterator<Container> inserter(Container& x, ranges::iterator_t<Container> i);
Returns: insert_­iterator<Container>(x, i).

23.5.3 Move iterators and sentinels [move.iterators]

Class template move_­iterator is an iterator adaptor with the same behavior as the underlying iterator except that its indirection operator implicitly converts the value returned by the underlying iterator's indirection operator to an rvalue.
Some generic algorithms can be called with move iterators to replace copying with moving.
[Example
:
list<string> s;
// populate the list s
vector<string> v1(s.begin(), s.end());          // copies strings into v1
vector<string> v2(make_move_iterator(s.begin()),
                  make_move_iterator(s.end())); // moves strings into v2
β€” end example
]

23.5.3.1 Class template move_­iterator [move.iterator]

namespace std {
  template<class Iterator>
  class move_iterator {
  public:
    using iterator_type     = Iterator;
    using iterator_concept  = input_iterator_tag;
    using iterator_category = see below;
    using value_type        = iter_value_t<Iterator>;
    using difference_type   = iter_difference_t<Iterator>;
    using pointer           = Iterator;
    using reference         = iter_rvalue_reference_t<Iterator>;

    constexpr move_iterator();
    constexpr explicit move_iterator(Iterator i);
    template<class U> constexpr move_iterator(const move_iterator<U>& u);
    template<class U> constexpr move_iterator& operator=(const move_iterator<U>& u);

    constexpr iterator_type base() const &;
    constexpr iterator_type base() &&;
    constexpr reference operator*() const;

    constexpr move_iterator& operator++();
    constexpr auto operator++(int);
    constexpr move_iterator& operator--();
    constexpr move_iterator operator--(int);

    constexpr move_iterator operator+(difference_type n) const;
    constexpr move_iterator& operator+=(difference_type n);
    constexpr move_iterator operator-(difference_type n) const;
    constexpr move_iterator& operator-=(difference_type n);
    constexpr reference operator[](difference_type n) const;

    template<sentinel_for<Iterator> S>
      friend constexpr bool
        operator==(const move_iterator& x, const move_sentinel<S>& y);
    template<sized_sentinel_for<Iterator> S>
      friend constexpr iter_difference_t<Iterator>
        operator-(const move_sentinel<S>& x, const move_iterator& y);
    template<sized_sentinel_for<Iterator> S>
      friend constexpr iter_difference_t<Iterator>
        operator-(const move_iterator& x, const move_sentinel<S>& y);
    friend constexpr iter_rvalue_reference_t<Iterator>
      iter_move(const move_iterator& i)
        noexcept(noexcept(ranges::iter_move(i.current)));
    template<indirectly_swappable<Iterator> Iterator2>
      friend constexpr void
        iter_swap(const move_iterator& x, const move_iterator<Iterator2>& y)
          noexcept(noexcept(ranges::iter_swap(x.current, y.current)));

  private:
    Iterator current;   // exposition only
  };
}
The member typedef-name iterator_­category denotes
  • random_­access_­iterator_­tag if the type iterator_­traits<​Iterator>​::​iterator_­category models derived_­from<random_­access_­iterator_­tag>, and
  • iterator_­traits<​Iterator>​::​iterator_­category otherwise.

23.5.3.2 Requirements [move.iter.requirements]

The template parameter Iterator shall either meet the Cpp17InputIterator requirements ([input.iterators]) or model input_­iterator ([iterator.concept.input]).
Additionally, if any of the bidirectional traversal functions are instantiated, the template parameter shall either meet the Cpp17BidirectionalIterator requirements ([bidirectional.iterators]) or model bidirectional_­iterator ([iterator.concept.bidir]).
If any of the random access traversal functions are instantiated, the template parameter shall either meet the Cpp17RandomAccessIterator requirements ([random.access.iterators]) or model random_­access_­iterator ([iterator.concept.random.access]).

23.5.3.3 Construction and assignment [move.iter.cons]

constexpr move_iterator();
Effects: Constructs a move_­iterator, value-initializing current.
Iterator operations applied to the resulting iterator have defined behavior if and only if the corresponding operations are defined on a value-initialized iterator of type Iterator.
constexpr explicit move_iterator(Iterator i);
Effects: Constructs a move_­iterator, initializing current with std​::​move(i).
template<class U> constexpr move_iterator(const move_iterator<U>& u);
Mandates: U is convertible to Iterator.
Effects: Constructs a move_­iterator, initializing current with u.base().
template<class U> constexpr move_iterator& operator=(const move_iterator<U>& u);
Mandates: U is convertible to Iterator.
Effects: Assigns u.base() to current.

23.5.3.4 Conversion [move.iter.op.conv]

constexpr Iterator base() const &;
Constraints: Iterator satisfies copy_­constructible.
Preconditions: Iterator models copy_­constructible.
Returns: current.
constexpr Iterator base() &&;
Returns: std​::​move(current).

23.5.3.5 Element access [move.iter.elem]

constexpr reference operator*() const;
Effects: Equivalent to: return ranges​::​iter_­move(current);
constexpr reference operator[](difference_type n) const;
Effects: Equivalent to: ranges​::​iter_­move(current + n);

23.5.3.6 Navigation [move.iter.nav]

constexpr move_iterator& operator++();
Effects: As if by ++current.
Returns: *this.
constexpr auto operator++(int);
Effects: If Iterator models forward_­iterator, equivalent to:
move_iterator tmp = *this;
++current;
return tmp;
Otherwise, equivalent to ++current.
constexpr move_iterator& operator--();
Effects: As if by --current.
Returns: *this.
constexpr move_iterator operator--(int);
Effects: As if by:
move_iterator tmp = *this;
--current;
return tmp;
constexpr move_iterator operator+(difference_type n) const;
Returns: move_­iterator(current + n).
constexpr move_iterator& operator+=(difference_type n);
Effects: As if by: current += n;
Returns: *this.
constexpr move_iterator operator-(difference_type n) const;
Returns: move_­iterator(current - n).
constexpr move_iterator& operator-=(difference_type n);
Effects: As if by: current -= n;
Returns: *this.

23.5.3.7 Comparisons [move.iter.op.comp]

template<class Iterator1, class Iterator2> constexpr bool operator==(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y); template<sentinel_­for<Iterator> S> friend constexpr bool operator==(const move_iterator& x, const move_sentinel<S>& y);
Constraints: x.base() == y.base() is well-formed and convertible to bool.
Returns: x.base() == y.base().
template<class Iterator1, class Iterator2> constexpr bool operator<(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);
Constraints: x.base() < y.base() is well-formed and convertible to bool.
Returns: x.base() < y.base().
template<class Iterator1, class Iterator2> constexpr bool operator>(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);
Constraints: y.base() < x.base() is well-formed and convertible to bool.
Returns: y < x.
template<class Iterator1, class Iterator2> constexpr bool operator<=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);
Constraints: y.base() < x.base() is well-formed and convertible to bool.
Returns: !(y < x).
template<class Iterator1, class Iterator2> constexpr bool operator>=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);
Constraints: x.base() < y.base() is well-formed and convertible to bool.
Returns: !(x < y).
template<class Iterator1, three_­way_­comparable_­with<Iterator1> Iterator2> constexpr compare_three_way_result_t<Iterator1, Iterator2> operator<=>(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);
Returns: x.base() <=> y.base().

23.5.3.8 Non-member functions [move.iter.nonmember]

template<class Iterator1, class Iterator2> constexpr auto operator-( const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y) -> decltype(x.base() - y.base()); template<sized_­sentinel_­for<Iterator> S> friend constexpr iter_difference_t<Iterator> operator-(const move_sentinel<S>& x, const move_iterator& y); template<sized_­sentinel_­for<Iterator> S> friend constexpr iter_difference_t<Iterator> operator-(const move_iterator& x, const move_sentinel<S>& y);
Returns: x.base() - y.base().
template<class Iterator> constexpr move_iterator<Iterator> operator+(iter_difference_t<Iterator> n, const move_iterator<Iterator>& x);
Constraints: x + n is well-formed and has type Iterator.
Returns: x + n.
friend constexpr iter_rvalue_reference_t<Iterator> iter_move(const move_iterator& i) noexcept(noexcept(ranges::iter_move(i.current)));
Effects: Equivalent to: return ranges​::​iter_­move(i.current);
template<indirectly_­swappable<Iterator> Iterator2> friend constexpr void iter_swap(const move_iterator& x, const move_iterator<Iterator2>& y) noexcept(noexcept(ranges::iter_swap(x.current, y.current)));
Effects: Equivalent to: ranges​::​iter_­swap(x.current, y.current).
template<class Iterator> constexpr move_iterator<Iterator> make_move_iterator(Iterator i);
Returns: move_­iterator<Iterator>(std​::​move(i)).

23.5.3.9 Class template move_­sentinel [move.sentinel]

Class template move_­sentinel is a sentinel adaptor useful for denoting ranges together with move_­iterator.
When an input iterator type I and sentinel type S model sentinel_­for<S, I>, move_­sentinel<S> and move_­iterator<I> model sentinel_­for<move_­sentinel<S>, move_­iterator<I>> as well.
[Example
:
A move_­if algorithm is easily implemented with copy_­if using move_­iterator and move_­sentinel:
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
         indirect_unary_predicate<I> Pred>
  requires indirectly_movable<I, O>
void move_if(I first, S last, O out, Pred pred) {
  std::ranges::copy_if(move_iterator<I>{first}, move_sentinel<S>{last}, out, pred);
}
β€” end example
]
namespace std {
  template<semiregular S>
  class move_sentinel {
  public:
    constexpr move_sentinel();
    constexpr explicit move_sentinel(S s);
    template<class S2>
      requires convertible_to<const S2&, S>
        constexpr move_sentinel(const move_sentinel<S2>& s);
    template<class S2>
      requires assignable_from<S&, const S2&>
        constexpr move_sentinel& operator=(const move_sentinel<S2>& s);

    constexpr S base() const;
  private:
    S last;     // exposition only
  };
}

23.5.3.10 Operations [move.sent.ops]

constexpr move_sentinel();
Effects: Value-initializes last.
If is_­trivially_­default_­constructible_­v<S> is true, then this constructor is a constexpr constructor.
constexpr explicit move_sentinel(S s);
Effects: Initializes last with std​::​move(s).
template<class S2> requires convertible_­to<const S2&, S> constexpr move_sentinel(const move_sentinel<S2>& s);
Effects: Initializes last with s.last.
template<class S2> requires assignable_­from<S&, const S2&> constexpr move_sentinel& operator=(const move_sentinel<S2>& s);
Effects: Equivalent to: last = s.last; return *this;
constexpr S base() const;
Returns: last.

23.5.4 Common iterators [iterators.common]

23.5.4.1 Class template common_­iterator [common.iterator]

Class template common_­iterator is an iterator/sentinel adaptor that is capable of representing a non-common range of elements (where the types of the iterator and sentinel differ) as a common range (where they are the same).
It does this by holding either an iterator or a sentinel, and implementing the equality comparison operators appropriately.
[Note
:
The common_­iterator type is useful for interfacing with legacy code that expects the begin and end of a range to have the same type.
β€” end note
]
[Example
:
template<class ForwardIterator>
void fun(ForwardIterator begin, ForwardIterator end);

list<int> s;
// populate the list s
using CI = common_iterator<counted_iterator<list<int>::iterator>, default_sentinel_t>;
// call fun on a range of 10 ints
fun(CI(counted_iterator(s.begin(), 10)), CI(default_sentinel));
β€” end example
]
namespace std {
  template<input_or_output_iterator I, sentinel_for<I> S>
    requires (!same_as<I, S> && copyable<I>)
  class common_iterator {
  public:
    constexpr common_iterator() = default;
    constexpr common_iterator(I i);
    constexpr common_iterator(S s);
    template<class I2, class S2>
      requires convertible_to<const I2&, I> && convertible_to<const S2&, S>
        constexpr common_iterator(const common_iterator<I2, S2>& x);

    template<class I2, class S2>
      requires convertible_to<const I2&, I> && convertible_to<const S2&, S> &&
               assignable_from<I&, const I2&> && assignable_from<S&, const S2&>
        common_iterator& operator=(const common_iterator<I2, S2>& x);

    decltype(auto) operator*();
    decltype(auto) operator*() const
      requires dereferenceable<const I>;
    decltype(auto) operator->() const
      requires see below;

    common_iterator& operator++();
    decltype(auto) operator++(int);

    template<class I2, sentinel_for<I> S2>
      requires sentinel_for<S, I2>
    friend bool operator==(
      const common_iterator& x, const common_iterator<I2, S2>& y);
    template<class I2, sentinel_for<I> S2>
      requires sentinel_for<S, I2> && equality_comparable_with<I, I2>
    friend bool operator==(
      const common_iterator& x, const common_iterator<I2, S2>& y);

    template<sized_sentinel_for<I> I2, sized_sentinel_for<I> S2>
      requires sized_sentinel_for<S, I2>
    friend iter_difference_t<I2> operator-(
      const common_iterator& x, const common_iterator<I2, S2>& y);

    friend iter_rvalue_reference_t<I> iter_move(const common_iterator& i)
      noexcept(noexcept(ranges::iter_move(declval<const I&>())))
        requires input_iterator<I>;
    template<indirectly_swappable<I> I2, class S2>
      friend void iter_swap(const common_iterator& x, const common_iterator<I2, S2>& y)
        noexcept(noexcept(ranges::iter_swap(declval<const I&>(), declval<const I2&>())));

  private:
    variant<I, S> v_;   // exposition only
  };

  template<class I, class S>
  struct incrementable_traits<common_iterator<I, S>> {
    using difference_type = iter_difference_t<I>;
  };

  template<input_iterator I, class S>
  struct iterator_traits<common_iterator<I, S>> {
    using iterator_concept = see below;
    using iterator_category = see below;
    using value_type = iter_value_t<I>;
    using difference_type = iter_difference_t<I>;
    using pointer = see below;
    using reference = iter_reference_t<I>;
  };
}

23.5.4.2 Associated types [common.iter.types]

The nested typedef-names of the specialization of iterator_­traits for common_­iterator<I, S> are defined as follows.
  • iterator_­concept denotes forward_­iterator_­tag if I models forward_­iterator; otherwise it denotes input_­iterator_­tag.
  • iterator_­category denotes forward_­iterator_­tag if iterator_­traits<I>​::​iterator_­category models derived_­from<forward_­iterator_­tag>; otherwise it denotes input_­iterator_­tag.
  • If the expression a.operator->() is well-formed, where a is an lvalue of type const common_­iterator<I, S>, then pointer denotes the type of that expression.
    Otherwise, pointer denotes void.

23.5.4.3 Constructors and conversions [common.iter.const]

constexpr common_iterator(I i);
Effects: Initializes v_­ as if by v_­{in_­place_­type<I>, std​::​move(i)}.
constexpr common_iterator(S s);
Effects: Initializes v_­ as if by v_­{in_­place_­type<S>, std​::​move(s)}.
template<class I2, class S2> requires convertible_­to<const I2&, I> && convertible_­to<const S2&, S> constexpr common_iterator(const common_iterator<I2, S2>& x);
Preconditions: x.v_­.valueless_­by_­exception() is false.
Effects: Initializes v_­ as if by v_­{in_­place_­index<i>, get<i>(x.v_­)}, where i is x.v_­.index().
template<class I2, class S2> requires convertible_­to<const I2&, I> && convertible_­to<const S2&, S> && assignable_­from<I&, const I2&> && assignable_­from<S&, const S2&> common_iterator& operator=(const common_iterator<I2, S2>& x);
Preconditions: x.v_­.valueless_­by_­exception() is false.
Effects: Equivalent to:
  • If v_­.index() == x.v_­.index(), then get<i>(v_­) = get<i>(x.v_­).
  • Otherwise, v_­.emplace<i>(get<i>(x.v_­)).
where i is x.v_­.index().
Returns: *this

23.5.4.4 Accessors [common.iter.access]

decltype(auto) operator*(); decltype(auto) operator*() const requires dereferenceable<const I>;
Preconditions: holds_­alternative<I>(v_­).
Effects: Equivalent to: return *get<I>(v_­);
decltype(auto) operator->() const requires see below;
The expression in the requires clause is equivalent to:
indirectly_readable<const I> &&
(requires(const I& i) { i.operator->(); } ||
 is_reference_v<iter_reference_t<I>> ||
 constructible_from<iter_value_t<I>, iter_reference_t<I>>)
Preconditions: holds_­alternative<I>(v_­).
Effects:
  • If I is a pointer type or if the expression get<I>(v_­).operator->() is well-formed, equivalent to: return get<I>(v_­);
  • Otherwise, if iter_­reference_­t<I> is a reference type, equivalent to:
    auto&& tmp = *get<I>(v_);
    return addressof(tmp);
    
  • Otherwise, equivalent to: return proxy(*get<I>(v_­)); where proxy is the exposition-only class:
    class proxy {
      iter_value_t<I> keep_;
      proxy(iter_reference_t<I>&& x)
        : keep_(std::move(x)) {}
    public:
      const iter_value_t<I>* operator->() const {
        return addressof(keep_);
      }
    };
    

23.5.4.5 Navigation [common.iter.nav]

common_iterator& operator++();
Preconditions: holds_­alternative<I>(v_­).
Effects: Equivalent to ++get<I>(v_­).
Returns: *this.
decltype(auto) operator++(int);
Preconditions: holds_­alternative<I>(v_­).
Effects: If I models forward_­iterator, equivalent to:
common_iterator tmp = *this;
++*this;
return tmp;
Otherwise, equivalent to: return get<I>(v_­)++;

23.5.4.6 Comparisons [common.iter.cmp]

template<class I2, sentinel_­for<I> S2> requires sentinel_­for<S, I2> friend bool operator==( const common_iterator& x, const common_iterator<I2, S2>& y);
Preconditions: x.v_­.valueless_­by_­exception() and y.v_­.valueless_­by_­exception() are each false.
Returns: true if i == j, and otherwise get<i>(x.v_­) == get<j>(y.v_­), where i is x.v_­.index() and j is y.v_­.index().
template<class I2, sentinel_­for<I> S2> requires sentinel_­for<S, I2> && equality_comparable_with<I, I2> friend bool operator==( const common_iterator& x, const common_iterator<I2, S2>& y);
Preconditions: x.v_­.valueless_­by_­exception() and y.v_­.valueless_­by_­exception() are each false.
Returns: true if i and j are each 1, and otherwise get<i>(x.v_­) == get<j>(y.v_­), where i is x.v_­.index() and j is y.v_­.index().
template<sized_­sentinel_­for<I> I2, sized_­sentinel_­for<I> S2> requires sized_­sentinel_­for<S, I2> friend iter_difference_t<I2> operator-( const common_iterator& x, const common_iterator<I2, S2>& y);
Preconditions: x.v_­.valueless_­by_­exception() and y.v_­.valueless_­by_­exception() are each false.
Returns: 0 if i and j are each 1, and otherwise get<i>(x.v_­) - get<j>(y.v_­), where i is x.v_­.index() and j is y.v_­.index().

23.5.4.7 Customizations [common.iter.cust]

friend iter_rvalue_reference_t<I> iter_move(const common_iterator& i) noexcept(noexcept(ranges::iter_move(declval<const I&>()))) requires input_­iterator<I>;
Preconditions: holds_­alternative<I>(v_­).
Effects: Equivalent to: return ranges​::​iter_­move(get<I>(i.v_­));
template<indirectly_­swappable<I> I2, class S2> friend void iter_swap(const common_iterator& x, const common_iterator<I2, S2>& y) noexcept(noexcept(ranges::iter_swap(declval<const I&>(), declval<const I2&>())));
Preconditions: holds_­alternative<I>(x.v_­) and holds_­alternative<I2>(y.v_­) are each true.
Effects: Equivalent to ranges​::​iter_­swap(get<I>(x.v_­), get<I2>(y.v_­)).

23.5.5 Default sentinels [default.sentinels]

namespace std { struct default_sentinel_t { }; }
Class default_­sentinel_­t is an empty type used to denote the end of a range.
It can be used together with iterator types that know the bound of their range (e.g., counted_­iterator ([counted.iterator])).

23.5.6 Counted iterators [iterators.counted]

23.5.6.1 Class template counted_­iterator [counted.iterator]

Class template counted_­iterator is an iterator adaptor with the same behavior as the underlying iterator except that it keeps track of the distance to the end of its range.
It can be used together with default_­sentinel in calls to generic algorithms to operate on a range of N elements starting at a given position without needing to know the end position a priori.
[Example
:
list<string> s;
// populate the list s with at least 10 strings
vector<string> v;
// copies 10 strings into v:
ranges::copy(counted_iterator(s.begin(), 10), default_sentinel, back_inserter(v));
β€” end example
]
Two values i1 and i2 of types counted_­iterator<I1> and counted_­iterator<I2> refer to elements of the same sequence if and only if next(i1.base(), i1.count()) and next(i2.base(), i2.count()) refer to the same (possibly past-the-end) element.
namespace std {
  template<input_or_output_iterator I>
  class counted_iterator {
  public:
    using iterator_type = I;

    constexpr counted_iterator() = default;
    constexpr counted_iterator(I x, iter_difference_t<I> n);
    template<class I2>
      requires convertible_to<const I2&, I>
        constexpr counted_iterator(const counted_iterator<I2>& x);

    template<class I2>
      requires assignable_from<I&, const I2&>
        constexpr counted_iterator& operator=(const counted_iterator<I2>& x);

    constexpr I base() const & requires copy_constructible<I>;
    constexpr I base() &&;
    constexpr iter_difference_t<I> count() const noexcept;
    constexpr decltype(auto) operator*();
    constexpr decltype(auto) operator*() const
      requires dereferenceable<const I>;

    constexpr counted_iterator& operator++();
    decltype(auto) operator++(int);
    constexpr counted_iterator operator++(int)
      requires forward_iterator<I>;
    constexpr counted_iterator& operator--()
      requires bidirectional_iterator<I>;
    constexpr counted_iterator operator--(int)
      requires bidirectional_iterator<I>;

    constexpr counted_iterator operator+(iter_difference_t<I> n) const
      requires random_access_iterator<I>;
    friend constexpr counted_iterator operator+(
      iter_difference_t<I> n, const counted_iterator& x)
        requires random_access_iterator<I>;
    constexpr counted_iterator& operator+=(iter_difference_t<I> n)
      requires random_access_iterator<I>;

    constexpr counted_iterator operator-(iter_difference_t<I> n) const
      requires random_access_iterator<I>;
    template<common_with<I> I2>
      friend constexpr iter_difference_t<I2> operator-(
        const counted_iterator& x, const counted_iterator<I2>& y);
    friend constexpr iter_difference_t<I> operator-(
      const counted_iterator& x, default_sentinel_t);
    friend constexpr iter_difference_t<I> operator-(
      default_sentinel_t, const counted_iterator& y);
    constexpr counted_iterator& operator-=(iter_difference_t<I> n)
      requires random_access_iterator<I>;

    constexpr decltype(auto) operator[](iter_difference_t<I> n) const
      requires random_access_iterator<I>;

    template<common_with<I> I2>
      friend constexpr bool operator==(
        const counted_iterator& x, const counted_iterator<I2>& y);
    friend constexpr bool operator==(
      const counted_iterator& x, default_sentinel_t);

    template<common_with<I> I2>
      friend constexpr strong_ordering operator<=>(
        const counted_iterator& x, const counted_iterator<I2>& y);

    friend constexpr iter_rvalue_reference_t<I> iter_move(const counted_iterator& i)
      noexcept(noexcept(ranges::iter_move(i.current)))
        requires input_iterator<I>;
    template<indirectly_swappable<I> I2>
      friend constexpr void iter_swap(const counted_iterator& x, const counted_iterator<I2>& y)
        noexcept(noexcept(ranges::iter_swap(x.current, y.current)));

  private:
    I current = I();                    // exposition only
    iter_difference_t<I> length = 0;    // exposition only
  };

  template<class I>
  struct incrementable_traits<counted_iterator<I>> {
    using difference_type = iter_difference_t<I>;
  };

  template<input_iterator I>
  struct iterator_traits<counted_iterator<I>> : iterator_traits<I> {
    using pointer = void;
  };
}

23.5.6.2 Constructors and conversions [counted.iter.const]

constexpr counted_iterator(I i, iter_difference_t<I> n);
Preconditions: n >= 0.
Effects: Initializes current with std​::​move(i) and length with n.
template<class I2> requires convertible_­to<const I2&, I> constexpr counted_iterator(const counted_iterator<I2>& x);
Effects: Initializes current with x.current and length with x.length.
template<class I2> requires assignable_­from<I&, const I2&> constexpr counted_iterator& operator=(const counted_iterator<I2>& x);
Effects: Assigns x.current to current and x.length to length.
Returns: *this.

23.5.6.3 Accessors [counted.iter.access]

constexpr I base() const & requires copy_constructible<I>;
Effects: Equivalent to: return current;
constexpr I base() &&;
Returns: std​::​move(current).
constexpr iter_difference_t<I> count() const noexcept;
Effects: Equivalent to: return length;

23.5.6.4 Element access [counted.iter.elem]

constexpr decltype(auto) operator*(); constexpr decltype(auto) operator*() const requires dereferenceable<const I>;
Effects: Equivalent to: return *current;
constexpr decltype(auto) operator[](iter_difference_t<I> n) const requires random_­access_­iterator<I>;
Preconditions: n < length.
Effects: Equivalent to: return current[n];

23.5.6.5 Navigation [counted.iter.nav]

constexpr counted_iterator& operator++();
Preconditions: length > 0.
Effects: Equivalent to:
++current;
--length;
return *this;
decltype(auto) operator++(int);
Preconditions: length > 0.
Effects: Equivalent to:
--length;
try { return current++; }
catch(...) { ++length; throw; }
constexpr counted_iterator operator++(int) requires forward_­iterator<I>;
Effects: Equivalent to:
counted_iterator tmp = *this;
++*this;
return tmp;
constexpr counted_iterator& operator--() requires bidirectional_­iterator<I>;
Effects: Equivalent to:
--current;
++length;
return *this;
constexpr counted_iterator operator--(int) requires bidirectional_­iterator<I>;
Effects: Equivalent to:
counted_iterator tmp = *this;
--*this;
return tmp;
constexpr counted_iterator operator+(iter_difference_t<I> n) const requires random_­access_­iterator<I>;
Effects: Equivalent to: return counted_­iterator(current + n, length - n);
friend constexpr counted_iterator operator+( iter_difference_t<I> n, const counted_iterator& x) requires random_­access_­iterator<I>;
Effects: Equivalent to: return x + n;
constexpr counted_iterator& operator+=(iter_difference_t<I> n) requires random_­access_­iterator<I>;
Preconditions: n <= length.
Effects: Equivalent to:
current += n;
length -= n;
return *this;
constexpr counted_iterator operator-(iter_difference_t<I> n) const requires random_­access_­iterator<I>;
Effects: Equivalent to: return counted_­iterator(current - n, length + n);
template<common_­with<I> I2> friend constexpr iter_difference_t<I2> operator-( const counted_iterator& x, const counted_iterator<I2>& y);
Preconditions: x and y refer to elements of the same sequence ([counted.iterator]).
Effects: Equivalent to: return y.length - x.length;
friend constexpr iter_difference_t<I> operator-( const counted_iterator& x, default_sentinel_t);
Effects: Equivalent to: return -x.length;
friend constexpr iter_difference_t<I> operator-( default_sentinel_t, const counted_iterator& y);
Effects: Equivalent to: return y.length;
constexpr counted_iterator& operator-=(iter_difference_t<I> n) requires random_­access_­iterator<I>;
Preconditions: -n <= length.
Effects: Equivalent to:
current -= n;
length += n;
return *this;

23.5.6.6 Comparisons [counted.iter.cmp]

template<common_­with<I> I2> friend constexpr bool operator==( const counted_iterator& x, const counted_iterator<I2>& y);
Preconditions: x and y refer to elements of the same sequence ([counted.iterator]).
Effects: Equivalent to: return x.length == y.length;
friend constexpr bool operator==( const counted_iterator& x, default_sentinel_t);
Effects: Equivalent to: return x.length == 0;
template<common_­with<I> I2> friend constexpr strong_ordering operator<=>( const counted_iterator& x, const counted_iterator<I2>& y);
Preconditions: x and y refer to elements of the same sequence ([counted.iterator]).
Effects: Equivalent to: return y.length <=> x.length;
[Note
:
The argument order in the Effects: element is reversed because length counts down, not up.
β€” end note
]

23.5.6.7 Customizations [counted.iter.cust]

friend constexpr iter_rvalue_reference_t<I> iter_move(const counted_iterator& i) noexcept(noexcept(ranges::iter_move(i.current))) requires input_­iterator<I>;
Effects: Equivalent to: return ranges​::​iter_­move(i.current);
template<indirectly_­swappable<I> I2> friend constexpr void iter_swap(const counted_iterator& x, const counted_iterator<I2>& y) noexcept(noexcept(ranges::iter_swap(x.current, y.current)));
Effects: Equivalent to ranges​::​iter_­swap(x.current, y.current).

23.5.7 Unreachable sentinel [unreachable.sentinels]

23.5.7.1 Class unreachable_­sentinel_­t [unreachable.sentinel]

Class unreachable_­sentinel_­t can be used with any weakly_­incrementable type to denote the β€œupper bound” of an unbounded interval.
[Example
:
char* p;
// set p to point to a character buffer containing newlines
char* nl = find(p, unreachable_sentinel, '\n');
Provided a newline character really exists in the buffer, the use of unreachable_­sentinel above potentially makes the call to find more efficient since the loop test against the sentinel does not require a conditional branch.
β€” end example
]
namespace std {
  struct unreachable_sentinel_t {
    template<weakly_incrementable I>
      friend constexpr bool operator==(unreachable_sentinel_t, const I&) noexcept
      { return false; }
  };
}