22 Iterators library [iterators]

22.3 Iterator requirements [iterator.requirements]

22.3.4 Iterator concepts [iterator.concepts]

22.3.4.1 General [iterator.concepts.general]

For a type I, let ITER_­TRAITS(I) denote the type I if iterator_­traits<I> names a specialization generated from the primary template.
Otherwise, ITER_­TRAITS(I) denotes iterator_­traits<I>.
  • If the qualified-id ITER_­TRAITS(I)::iterator_­concept is valid and names a type, then ITER_­CONCEPT(I) denotes that type.
  • Otherwise, if the qualified-id ITER_­TRAITS(I)::iterator_­category is valid and names a type, then ITER_­CONCEPT(I) denotes that type.
  • Otherwise, if iterator_­traits<I> names a specialization generated from the primary template, then ITER_­CONCEPT(I) denotes random_­access_­iterator_­tag.
  • Otherwise, ITER_­CONCEPT(I) does not denote a type.
[Note
:
ITER_­TRAITS enables independent syntactic determination of an iterator's category and concept.
end note
]
[Example
:
struct I {
  using value_type = int;
  using difference_type = int;

  int operator*() const;
  I& operator++();
  I operator++(int);
  I& operator--();
  I operator--(int);

  bool operator==(I) const;
  bool operator!=(I) const;
};
iterator_­traits<I>::iterator_­category denotes input_­iterator_­tag, and ITER_­CONCEPT(I) denotes random_­access_­iterator_­tag.
end example
]

22.3.4.2 Concept Readable [iterator.concept.readable]

Types that are readable by applying operator* model the Readable concept, including pointers, smart pointers, and iterators.
template<class In>
  concept Readable =
    requires {
      typename iter_value_t<In>;
      typename iter_reference_t<In>;
      typename iter_rvalue_reference_t<In>;
    } &&
    CommonReference<iter_reference_t<In>&&, iter_value_t<In>&> &&
    CommonReference<iter_reference_t<In>&&, iter_rvalue_reference_t<In>&&> &&
    CommonReference<iter_rvalue_reference_t<In>&&, const iter_value_t<In>&>;
Given a value i of type I, I models Readable only if the expression *i is equality-preserving.
[Note
:
The expression *i is indirectly required to be valid via the exposition-only dereferenceable concept ([iterator.synopsis]).
end note
]

22.3.4.3 Concept Writable [iterator.concept.writable]

The Writable concept specifies the requirements for writing a value into an iterator's referenced object.
template<class Out, class T>
  concept Writable =
    requires(Out&& o, T&& t) {
      *o = std::forward<T>(t); // not required to be equality-preserving
      *std::forward<Out>(o) = std::forward<T>(t); // not required to be equality-preserving
      const_cast<const iter_reference_t<Out>&&>(*o) =
        std::forward<T>(t); // not required to be equality-preserving
      const_cast<const iter_reference_t<Out>&&>(*std::forward<Out>(o)) =
        std::forward<T>(t); // not required to be equality-preserving
    };
Let E be an an expression such that decltype((E)) is T, and let o be a dereferenceable object of type Out.
Out and T model Writable<Out, T> only if
  • If Out and T model Readable<Out> && Same<iter_­value_­t<Out>, decay_­t<T>>, then *o after any above assignment is equal to the value of E before the assignment.
After evaluating any above assignment expression, o is not required to be dereferenceable.
If E is an xvalue ([basic.lval]), the resulting state of the object it denotes is valid but unspecified ([lib.types.movedfrom]).
[Note
:
The only valid use of an operator* is on the left side of the assignment statement.
Assignment through the same value of the writable type happens only once.
end note
]
[Note
:
Writable has the awkward const_­cast expressions to reject iterators with prvalue non-proxy reference types that permit rvalue assignment but do not also permit const rvalue assignment.
Consequently, an iterator type I that returns std::string by value does not model Writable<I, std::string>.
end note
]

22.3.4.4 Concept WeaklyIncrementable [iterator.concept.winc]

The WeaklyIncrementable concept specifies the requirements on types that can be incremented with the pre- and post-increment operators.
The increment operations are not required to be equality-preserving, nor is the type required to be EqualityComparable.
template<class I>
  concept WeaklyIncrementable =
    Semiregular<I> &&
    requires(I i) {
      typename iter_difference_t<I>;
      requires SignedIntegral<iter_difference_t<I>>;
      { ++i } -> Same<I&>; // not required to be equality-preserving
      i++; // not required to be equality-preserving
    };
Let i be an object of type I.
When i is in the domain of both pre- and post-increment, i is said to be incrementable.
I models WeaklyIncrementable<I> only if
  • The expressions ++i and i++ have the same domain.
  • If i is incrementable, then both ++i and i++ advance i to the next element.
  • If i is incrementable, then addressof(++i) is equal to addressof(i).
[Note
:
For WeaklyIncrementable types, a equals b does not imply that ++a equals ++b.
(Equality does not guarantee the substitution property or referential transparency.)
Algorithms on weakly incrementable types should never attempt to pass through the same incrementable value twice.
They should be single-pass algorithms.
These algorithms can be used with istreams as the source of the input data through the istream_­iterator class template.
end note
]

22.3.4.5 Concept Incrementable [iterator.concept.inc]

The Incrementable concept specifies requirements on types that can be incremented with the pre- and post-increment operators.
The increment operations are required to be equality-preserving, and the type is required to be EqualityComparable.
[Note
:
This supersedes the annotations on the increment expressions in the definition of WeaklyIncrementable.
end note
]
template<class I>
  concept Incrementable =
    Regular<I> &&
    WeaklyIncrementable<I> &&
    requires(I i) {
      { i++ } -> Same<I>;
    };
Let a and b be incrementable objects of type I.
I models Incrementable only if
  • If bool(a == b) then bool(a++ == b).
  • If bool(a == b) then bool(((void)a++, a) == ++b).
[Note
:
The requirement that a equals b implies ++a equals ++b (which is not true for weakly incrementable types) allows the use of multi-pass one-directional algorithms with types that model Incrementable.
end note
]

22.3.4.6 Concept Iterator [iterator.concept.iterator]

The Iterator concept forms the basis of the iterator concept taxonomy; every iterator models Iterator.
This concept specifies operations for dereferencing and incrementing an iterator.
Most algorithms will require additional operations to compare iterators with sentinels ([iterator.concept.sentinel]), to read ([iterator.concept.input]) or write ([iterator.concept.output]) values, or to provide a richer set of iterator movements ([iterator.concept.forward], [iterator.concept.bidir], [iterator.concept.random.access]).
template<class I>
  concept Iterator =
    requires(I i) {
      { *i } -> can-reference;
    } &&
    WeaklyIncrementable<I>;

22.3.4.7 Concept Sentinel [iterator.concept.sentinel]

The Sentinel concept specifies the relationship between an Iterator type and a Semiregular type whose values denote a range.
template<class S, class I> concept Sentinel = Semiregular<S> && Iterator<I> && weakly-equality-comparable-with<S, I>; // See [concept.equalitycomparable]
Let s and i be values of type S and I such that [i, s) denotes a range.
Types S and I model Sentinel<S, I> only if
  • i == s is well-defined.
  • If bool(i != s) then i is dereferenceable and [++i, s) denotes a range.
The domain of == is not static.
Given an iterator i and sentinel s such that [i, s) denotes a range and i != s, i and s are not required to continue to denote a range after incrementing any other iterator equal to i.
Consequently, i == s is no longer required to be well-defined.

22.3.4.8 Concept SizedSentinel [iterator.concept.sizedsentinel]

The SizedSentinel concept specifies requirements on an Iterator and a Sentinel that allow the use of the - operator to compute the distance between them in constant time.
template<class S, class I> concept SizedSentinel = Sentinel<S, I> && !disable_sized_sentinel<remove_cv_t<S>, remove_cv_t<I>> && requires(const I& i, const S& s) { { s - i } -> Same<iter_difference_t<I>>; { i - s } -> Same<iter_difference_t<I>>; };
Let i be an iterator of type I, and s a sentinel of type S such that [i, s) denotes a range.
Let N be the smallest number of applications of ++i necessary to make bool(i == s) be true.
S and I model SizedSentinel<S, I> only if
  • If N is representable by iter_­difference_­t<I>, then s - i is well-defined and equals N.
  • If is representable by iter_­difference_­t<I>, then i - s is well-defined and equals .
[Note
:
disable_­sized_­sentinel allows use of sentinels and iterators with the library that satisfy but do not in fact model SizedSentinel.
end note
]
[Example
:
The SizedSentinel concept is modeled by pairs of RandomAccessIterators ([iterator.concept.random.access]) and by counted iterators and their sentinels ([counted.iterator]).
end example
]

22.3.4.9 Concept InputIterator [iterator.concept.input]

The InputIterator concept defines requirements for a type whose referenced values can be read (from the requirement for Readable ([iterator.concept.readable])) and which can be both pre- and post-incremented.
[Note
:
Unlike the Cpp17InputIterator requirements ([input.iterators]), the InputIterator concept does not need equality comparison since iterators are typically compared to sentinels.
end note
]
template<class I>
  concept InputIterator =
    Iterator<I> &&
    Readable<I> &&
    requires { typename ITER_CONCEPT(I); } &&
    DerivedFrom<ITER_CONCEPT(I), input_iterator_tag>;

22.3.4.10 Concept OutputIterator [iterator.concept.output]

The OutputIterator concept defines requirements for a type that can be used to write values (from the requirement for Writable ([iterator.concept.writable])) and which can be both pre- and post-incremented.
[Note
:
Output iterators are not required to model EqualityComparable.
end note
]
template<class I, class T>
  concept OutputIterator =
    Iterator<I> &&
    Writable<I, T> &&
    requires(I i, T&& t) {
      *i++ = std::forward<T>(t); // not required to be equality-preserving
    };
Let E be an expression such that decltype((E)) is T, and let i be a dereferenceable object of type I.
I and T model OutputIterator<I, T> only if *i++ = E; has effects equivalent to:
  *i = E;
  ++i;
[Note
:
Algorithms on output iterators should never attempt to pass through the same iterator twice.
They should be single-pass algorithms.
end note
]

22.3.4.11 Concept ForwardIterator [iterator.concept.forward]

The ForwardIterator concept adds equality comparison and the multi-pass guarantee, specified below.
template<class I>
  concept ForwardIterator =
    InputIterator<I> &&
    DerivedFrom<ITER_CONCEPT(I), forward_iterator_tag> &&
    Incrementable<I> &&
    Sentinel<I, I>;
The domain of == for forward iterators is that of iterators over the same underlying sequence.
However, value-initialized iterators of the same type may be compared and shall compare equal to other value-initialized iterators of the same type.
[Note
:
Value-initialized iterators behave as if they refer past the end of the same empty sequence.
end note
]
Pointers and references obtained from a forward iterator into a range [i, s) shall remain valid while [i, s) continues to denote a range.
Two dereferenceable iterators a and b of type X offer the multi-pass guarantee if:
  • a == b implies ++a == ++b and
  • The expression ((void)[](X x){++x;}(a), *a) is equivalent to the expression *a.
[Note
:
The requirement that a == b implies ++a == ++b and the removal of the restrictions on the number of assignments through a mutable iterator (which applies to output iterators) allow the use of multi-pass one-directional algorithms with forward iterators.
end note
]

22.3.4.12 Concept BidirectionalIterator [iterator.concept.bidir]

The BidirectionalIterator concept adds the ability to move an iterator backward as well as forward.
template<class I>
  concept BidirectionalIterator =
    ForwardIterator<I> &&
    DerivedFrom<ITER_CONCEPT(I), bidirectional_iterator_tag> &&
    requires(I i) {
      { --i } -> Same<I&>;
      { i-- } -> Same<I>;
    };
A bidirectional iterator r is decrementable if and only if there exists some q such that ++q == r.
Decrementable iterators r shall be in the domain of the expressions --r and r--.
Let a and b be equal objects of type I.
I models BidirectionalIterator only if:
  • If a and b are decrementable, then all of the following are true:
    • addressof(--a) == addressof(a)
    • bool(a-- == b)
    • after evaluating both a-- and --b, bool(a == b) is still true
    • bool(++(--a) == b)
  • If a and b are incrementable, then bool(--(++a) == b).

22.3.4.13 Concept RandomAccessIterator [iterator.concept.random.access]

The RandomAccessIterator concept adds support for constant-time advancement with +=, +, -=, and -, as well as the computation of distance in constant time with -.
Random access iterators also support array notation via subscripting.
template<class I>
  concept RandomAccessIterator =
    BidirectionalIterator<I> &&
    DerivedFrom<ITER_CONCEPT(I), random_access_iterator_tag> &&
    StrictTotallyOrdered<I> &&
    SizedSentinel<I, I> &&
    requires(I i, const I j, const iter_difference_t<I> n) {
      { i += n } -> Same<I&>;
      { j +  n } -> Same<I>;
      { n +  j } -> Same<I>;
      { i -= n } -> Same<I&>;
      { j -  n } -> Same<I>;
      {  j[n]  } -> Same<iter_reference_t<I>>;
    };
Let a and b be valid iterators of type I such that b is reachable from a after n applications of ++a, let D be iter_­difference_­t<I>, and let n denote a value of type D.
I models RandomAccessIterator only if
  • (a += n) is equal to b.
  • addressof(a += n) is equal to addressof(a).
  • (a + n) is equal to (a += n).
  • For any two positive values x and y of type D, if (a + D(x + y)) is valid, then (a + D(x + y)) is equal to ((a + x) + y).
  • (a + D(0)) is equal to a.
  • If (a + D(n - 1)) is valid, then (a + n) is equal to ++(a + D(n - 1)).
  • (b += -n) is equal to a.
  • (b -= n) is equal to a.
  • addressof(b -= n) is equal to addressof(b).
  • (b - n) is equal to (b -= n).
  • If b is dereferenceable, then a[n] is valid and is equal to *b.
  • bool(a <= b) is true.

22.3.4.14 Concept ContiguousIterator [iterator.concept.contiguous]

The ContiguousIterator concept provides a guarantee that the denoted elements are stored contiguously in memory.
template<class I>
  concept ContiguousIterator =
    RandomAccessIterator<I> &&
    DerivedFrom<ITER_CONCEPT(I), contiguous_iterator_tag> &&
    is_lvalue_reference_v<iter_reference_t<I>> &&
    Same<iter_value_t<I>, remove_cvref_t<iter_reference_t<I>>>;
Let a and b be dereferenceable iterators of type I such that b is reachable from a, and let D be iter_­difference_­t<I>.
The type I models ContiguousIterator only if addressof(*(a + D(b - a))) is equal to addressof(*a) + D(b - a).