For a type I, let ITER_TRAITS(I) denote
the type I if iterator_traits<I> names
a specialization generated from the primary template.

- 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

: *end note*

]ITER_TRAITS enables independent syntactic determination
of an iterator's category and concept.

— [ Example

: — *end 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; };iterator_traits<I>::iterator_category denotes input_iterator_tag, and ITER_CONCEPT(I) denotes random_access_iterator_tag.

Types that are indirectly readable by applying operator*
model the indirectly_readable concept, including
pointers, smart pointers, and iterators.

template<class In> concept indirectly-readable-impl = requires(const In in) { typename iter_value_t<In>; typename iter_reference_t<In>; typename iter_rvalue_reference_t<In>; { *in } -> same_as<iter_reference_t<In>>; { ranges::iter_move(in) } -> same_as<iter_rvalue_reference_t<In>>; } && common_reference_with<iter_reference_t<In>&&, iter_value_t<In>&> && common_reference_with<iter_reference_t<In>&&, iter_rvalue_reference_t<In>&&> && common_reference_with<iter_rvalue_reference_t<In>&&, const iter_value_t<In>&>;

template<class In> concept indirectly_readable = indirectly-readable-impl<remove_cvref_t<In>>;

The indirectly_writable concept specifies the requirements
for writing a value into an iterator's referenced object.

template<class Out, class T> concept indirectly_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 expression such that decltype((E)) is T,
and let o be a dereferenceable object of type Out.

If E is an xvalue ([basic.lval]), the resulting
state of the object it denotes is valid but unspecified ([lib.types.movedfrom]).

[ Note

: *end note*

]indirectly_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 indirectly_writable<I, std::string>.

— The weakly_incrementable 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 equality_comparable.

template<class T> inline constexpr bool is-integer-like = see below; // exposition only template<class T> inline constexpr bool is-signed-integer-like = see below; // exposition only template<class I> concept weakly_incrementable = default_initializable<I> && movable<I> && requires(I i) { typename iter_difference_t<I>; requires is-signed-integer-like<iter_difference_t<I>>; { ++i } -> same_as<I&>; // not required to be equality-preserving i++; // not required to be equality-preserving };

A type I is an *integer-class type*
if it is in a set of implementation-defined class types
that behave as integer types do, as defined in below.

The range of representable values of an integer-class type
is the continuous set of values over which it is defined.

The values 0 and 1 are part of the range of every integer-class type.

If any negative numbers are part of the range,
the type is a *signed-integer-class type*;
otherwise, it is an *unsigned-integer-class type*.

For every integer-class type I,
let B(I) be a hypothetical extended integer type
of the same signedness with the smallest width ([basic.fundamental])
capable of representing the same range of values.

Let a and b be objects of integer-class type I,
let x and y be objects of type B(I) as described above
that represent the same values as a and b respectively, and
let c be an lvalue of any integral type.

- For every unary operator @ for which the expression @x is well-formed, @a shall also be well-formed and have the same value, effects, and value category as @x provided that value is representable by I.
- For every assignment operator @= for which c @= x is well-formed, c @= a shall also be well-formed and shall have the same value and effects as c @= x.
- For every binary operator @ for which x @ y is well-formed, a @ b shall also be well-formed and shall have the same value, effects, and value category as x @ y provided that value is representable by I.

Expressions of integer-class type are
explicitly convertible to any integral type.

Expressions of integral type are
both implicitly and explicitly convertible to any integer-class type.

Conversions between integral and integer-class types
do not exit via an exception.

An expression E of integer-class type I is
contextually convertible to bool
as if by bool(E != I(0)).

All integer-class types model
regular ([concepts.object]) and
totally_ordered ([concept.totallyordered]).

For every (possibly cv-qualified) integer-class type I,
numeric_limits<I> is specialized such that:

- numeric_limits<I>::is_specialized is true,
- numeric_limits<I>::is_signed is true if and only if I is a signed-integer-class type,
- numeric_limits<I>::is_integer is true,
- numeric_limits<I>::is_exact is true,
- numeric_limits<I>::digits is equal to the width of the integer-class type,
- numeric_limits<I>::digits10 is equal to static_cast<int>(digits * log10(2)), and
- numeric_limits<I>::min() and numeric_limits<I>::max() return the lowest and highest representable values of I, respectively, and numeric_limits<I>::lowest() returns numeric_limits<I>::min().

A type I is *signed-integer-like*
if it models signed_integral<I> or
if it is a signed-integer-class type.

A type I is *unsigned-integer-like*
if it models unsigned_integral<I> or
if it is an unsigned-integer-class type.

[ Note

: *end note*

](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.

— 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 equality_comparable.

[ Note

: *end note*

]This supersedes the annotations on the increment expressions
in the definition of weakly_incrementable.

— template<class I> concept incrementable = regular<I> && weakly_incrementable<I> && requires(I i) { { i++ } -> same_as<I>; };

The input_or_output_iterator concept forms the basis
of the iterator concept taxonomy; every iterator models input_or_output_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 input_or_output_iterator = requires(I i) { { *i } -> can-reference; } && weakly_incrementable<I>;

The sentinel_for concept specifies the relationship
between an input_or_output_iterator type and a semiregular type
whose values denote a range.

```
template<class S, class I>
concept sentinel_for =
semiregular<S> &&
input_or_output_iterator<I> &&
weakly-equality-comparable-with<S, I>; // See [concept.equalitycomparable]
```

The sized_sentinel_for concept specifies
requirements on an input_or_output_iterator type I and
a corresponding sentinel_for<I>
that allow the use of the - operator to compute the distance
between them in constant time.

```
template<class S, class I>
concept sized_sentinel_for =
sentinel_for<S, I> &&
!disable_sized_sentinel_for<remove_cv_t<S>, remove_cv_t<I>> &&
requires(const I& i, const S& s) {
{ s - i } -> same_as<iter_difference_t<I>>;
{ i - s } -> same_as<iter_difference_t<I>>;
};
```

```
template<class S, class I>
inline constexpr bool disable_sized_sentinel_for = false;
```

Remarks:
Pursuant to [namespace.std],
users may specialize disable_sized_sentinel_for
for cv-unqualified non-array object types S and I
if S and/or I is a program-defined type.

Such specializations shall
be usable in constant expressions ([expr.const]) and
have type const bool.

[ Example

: *end example*

]The sized_sentinel_for concept is modeled by pairs of
random_access_iterators ([iterator.concept.random.access]) and by
counted iterators and their sentinels ([counted.iterator]).

— The input_iterator concept defines requirements for a type
whose referenced values can be read (from the requirement for
indirectly_readable ([iterator.concept.readable]))
and which can be both pre- and post-incremented.

[ Note

: *end note*

]Unlike the Cpp17InputIterator requirements ([input.iterators]),
the input_iterator concept does not need
equality comparison since iterators are typically compared to sentinels.

— template<class I> concept input_iterator = input_or_output_iterator<I> && indirectly_readable<I> && requires { typename ITER_CONCEPT(I); } && derived_from<ITER_CONCEPT(I), input_iterator_tag>;

The output_iterator concept defines requirements for a type that
can be used to write values (from the requirement for
indirectly_writable ([iterator.concept.writable]))
and which can be both pre- and post-incremented.

template<class I, class T> concept output_iterator = input_or_output_iterator<I> && indirectly_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.

The forward_iterator concept adds
copyability, equality comparison, and
the multi-pass guarantee, specified below.

template<class I> concept forward_iterator = input_iterator<I> && derived_from<ITER_CONCEPT(I), forward_iterator_tag> && incrementable<I> && sentinel_for<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.

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.

The bidirectional_iterator concept adds the ability
to move an iterator backward as well as forward.

template<class I> concept bidirectional_iterator = forward_iterator<I> && derived_from<ITER_CONCEPT(I), bidirectional_iterator_tag> && requires(I i) { { --i } -> same_as<I&>; { i-- } -> same_as<I>; };

The random_access_iterator 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 random_access_iterator = bidirectional_iterator<I> && derived_from<ITER_CONCEPT(I), random_access_iterator_tag> && totally_ordered<I> && sized_sentinel_for<I, I> && requires(I i, const I j, const iter_difference_t<I> n) { { i += n } -> same_as<I&>; { j + n } -> same_as<I>; { n + j } -> same_as<I>; { i -= n } -> same_as<I&>; { j - n } -> same_as<I>; { j[n] } -> same_as<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 random_access_iterator 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 [](I c){ return ++c; }(a + D(n - 1)).
- (b += D(-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.

The contiguous_iterator concept provides a guarantee that
the denoted elements are stored contiguously in memory.

template<class I> concept contiguous_iterator = random_access_iterator<I> && derived_from<ITER_CONCEPT(I), contiguous_iterator_tag> && is_lvalue_reference_v<iter_reference_t<I>> && same_as<iter_value_t<I>, remove_cvref_t<iter_reference_t<I>>> && requires(const I& i) { { to_address(i) } -> same_as<add_pointer_t<iter_reference_t<I>>>; };

Let a and b be dereferenceable iterators and
c be a non-dereferenceable iterator of type I
such that b is reachable from a and
c is reachable from b,
and let D be iter_difference_t<I>.