Contiguous | → Random Access | → Bidirectional | → Forward | → Input |
→ Output |
iter_difference_t<WI>be defined as the incrementable type's difference type.
namespace std { template<class> struct incrementable_traits { }; template<class T> requires is_object_v<T> struct incrementable_traits<T*> { using difference_type = ptrdiff_t; }; template<class I> struct incrementable_traits<const I> : incrementable_traits<I> { }; template<class T> requires requires { typename T::difference_type; } struct incrementable_traits<T> { using difference_type = typename T::difference_type; }; template<class T> requires (!requires { typename T::difference_type; } && requires(const T& a, const T& b) { { a - b } -> Integral; }) struct incrementable_traits<T> { using difference_type = make_signed_t<decltype(declval<T>() - declval<T>())>; }; template<class T> using iter_difference_t = see below; }
iter_value_t<R>be defined as the readable type's value type.
template<class> struct cond-value-type { }; // exposition only template<class T> requires is_object_v<T> struct cond-value-type { using value_type = remove_cv_t<T>; }; template<class> struct readable_traits { }; template<class T> struct readable_traits<T*> : cond-value-type<T> { }; template<class I> requires is_array_v<I> struct readable_traits<I> { using value_type = remove_cv_t<remove_extent_t<I>>; }; template<class I> struct readable_traits<const I> : readable_traits<I> { }; template<class T> requires requires { typename T::value_type; } struct readable_traits<T> : cond-value-type<typename T::value_type> { }; template<class T> requires requires { typename T::element_type; } struct readable_traits<T> : cond-value-type<typename T::element_type> { }; template<class T> using iter_value_t = see below;
iterator_traits<I>::iterator_categorybe defined as the iterator's iterator category.
iterator_traits<I>::pointer iterator_traits<I>::referenceshall be defined as the iterator's pointer and reference types; that is, for an iterator object a of class type, the same type as decltype(a.operator->()) and decltype(*a), respectively.
iterator_traits<I>::value_type iterator_traits<I>::difference_type iterator_traits<I>::referencemay be defined as void.
template<class I> concept cpp17-iterator = Copyable<I> && requires(I i) { { *i } -> can-reference; { ++i } -> Same<I&>; { *i++ } -> can-reference; }; template<class I> concept cpp17-input-iterator = cpp17-iterator<I> && EqualityComparable<I> && requires(I i) { typename incrementable_traits<I>::difference_type; typename readable_traits<I>::value_type; typename common_reference_t<iter_reference_t<I>&&, typename readable_traits<I>::value_type&>; *i++; typename common_reference_t<decltype(*i++)&&, typename readable_traits<I>::value_type&>; requires SignedIntegral<typename incrementable_traits<I>::difference_type>; }; template<class I> concept cpp17-forward-iterator = cpp17-input-iterator<I> && Constructible<I> && is_lvalue_reference_v<iter_reference_t<I>> && Same<remove_cvref_t<iter_reference_t<I>>, typename readable_traits<I>::value_type> && requires(I i) { { i++ } -> const I&; { *i++ } -> Same<iter_reference_t<I>>; }; template<class I> concept cpp17-bidirectional-iterator = cpp17-forward-iterator<I> && requires(I i) { { --i } -> Same<I&>; { i-- } -> const I&; { *i-- } -> Same<iter_reference_t<I>>; }; template<class I> concept cpp17-random-access-iterator = cpp17-bidirectional-iterator<I> && StrictTotallyOrdered<I> && requires(I i, typename incrementable_traits<I>::difference_type n) { { i += n } -> Same<I&>; { i -= n } -> Same<I&>; { i + n } -> Same<I>; { n + i } -> Same<I>; { i - n } -> Same<I>; { i - i } -> Same<decltype(n)>; { i[n] } -> iter_reference_t<I>; };
using iterator_category = typename I::iterator_category; using value_type = typename I::value_type; using difference_type = typename I::difference_type; using pointer = see below; using reference = typename I::reference;
using iterator_category = see below; using value_type = typename readable_traits<I>::value_type; using difference_type = typename incrementable_traits<I>::difference_type; using pointer = see below; using reference = see below;
using iterator_category = output_iterator_tag; using value_type = void; using difference_type = see below; using pointer = void; using reference = void;
namespace std { template<class T> requires is_object_v<T> struct iterator_traits<T*> { using iterator_concept = contiguous_iterator_tag; using iterator_category = random_access_iterator_tag; using value_type = remove_cv_t<T>; using difference_type = ptrdiff_t; using pointer = T*; using reference = T&; }; }
template<class BI> void reverse(BI first, BI last) { typename iterator_traits<BI>::difference_type n = distance(first, last); --n; while(n > 0) { typename iterator_traits<BI>::value_type tmp = *first; *first++ = *--last; *last = tmp; n -= 2; } }— end example
template<class X, class Y>
constexpr iter_value_t<remove_reference_t<X>> iter-exchange-move(X&& x, Y&& y)
noexcept(noexcept(iter_value_t<remove_reference_t<X>>(iter_move(x))) &&
noexcept(*x = iter_move(y)));
iter_value_t<remove_reference_t<X>> old_value(iter_move(x)); *x = iter_move(y); return old_value;
template<class I1, class I2> void iter_swap(I1, I2) = delete;and does not include a declaration of ranges::iter_swap.
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.
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>&>;
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 };
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 };
template<class I> concept Incrementable = Regular<I> && WeaklyIncrementable<I> && requires(I i) { { i++ } -> Same<I>; };
template<class I> concept Iterator = requires(I i) { { *i } -> can-reference; } && WeaklyIncrementable<I>;
template<class S, class I>
concept Sentinel =
Semiregular<S> &&
Iterator<I> &&
weakly-equality-comparable-with<S, I>; // See [concept.equalitycomparable]
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>>;
};
template<class I> concept InputIterator = Iterator<I> && Readable<I> && requires { typename ITER_CONCEPT(I); } && DerivedFrom<ITER_CONCEPT(I), input_iterator_tag>;
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 };
*i = E; ++i;
template<class I> concept ForwardIterator = InputIterator<I> && DerivedFrom<ITER_CONCEPT(I), forward_iterator_tag> && Incrementable<I> && Sentinel<I, I>;
template<class I> concept BidirectionalIterator = ForwardIterator<I> && DerivedFrom<ITER_CONCEPT(I), bidirectional_iterator_tag> && requires(I i) { { --i } -> Same<I&>; { i-- } -> Same<I>; };
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>>; };
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>>>;
Expression | Return type | Operational | Assertion/note |
semantics | pre-/post-condition | ||
a != b | contextually convertible to bool | !(a == b) | |
*a | reference, convertible to T | ||
a->m | (*a).m | ||
++r | X& | Ensures: r is dereferenceable or r is past-the-end; any copies of the previous value of r are no longer required to be dereferenceable nor to be in the domain of ==. | |
(void)r++ | equivalent to (void)++r | ||
*r++ | convertible to T | { T tmp = *r; ++r; return tmp; } |
Expression | Return type | Operational | Assertion/note |
semantics | pre-/post-condition | ||
r++ | convertible to const X& | { X tmp = r; ++r; return tmp; } | |
*r++ | reference |
Expression | Return type | Operational | Assertion/note |
semantics | pre-/post-condition | ||
--r | X& | ||
r-- | convertible to const X& | { X tmp = r; --r; return tmp; } | |
*r-- | reference |
Expression | Return type | Operational | Assertion/note |
semantics | pre-/post-condition | ||
r += n | X& | { difference_type m = n; if (m >= 0) while (m--) ++r; else while (m++) --r; return r; } | |
a + n n + a | X | { X tmp = a; return tmp += n; } | a + n == n + a. |
r -= n | X& | return r += -n; | |
a - n | X | { X tmp = a; return tmp -= n; } | |
b - a | difference_type | return n | |
a[n] | convertible to reference | *(a + n) | |
a < b | contextually
convertible to bool | b - a > 0 | < is a total ordering relation |
a > b | contextually
convertible to bool | b < a | |
a >= b | contextually
convertible to bool | !(a < b) | |
a <= b | contextually
convertible to bool. | !(a > b) |
namespace std { template<class F, class I> concept IndirectUnaryInvocable = Readable<I> && CopyConstructible<F> && Invocable<F&, iter_value_t<I>&> && Invocable<F&, iter_reference_t<I>> && Invocable<F&, iter_common_reference_t<I>> && CommonReference< invoke_result_t<F&, iter_value_t<I>&>, invoke_result_t<F&, iter_reference_t<I>>>; template<class F, class I> concept IndirectRegularUnaryInvocable = Readable<I> && CopyConstructible<F> && RegularInvocable<F&, iter_value_t<I>&> && RegularInvocable<F&, iter_reference_t<I>> && RegularInvocable<F&, iter_common_reference_t<I>> && CommonReference< invoke_result_t<F&, iter_value_t<I>&>, invoke_result_t<F&, iter_reference_t<I>>>; template<class F, class I> concept IndirectUnaryPredicate = Readable<I> && CopyConstructible<F> && Predicate<F&, iter_value_t<I>&> && Predicate<F&, iter_reference_t<I>> && Predicate<F&, iter_common_reference_t<I>>; template<class F, class I1, class I2 = I1> concept IndirectRelation = Readable<I1> && Readable<I2> && CopyConstructible<F> && Relation<F&, iter_value_t<I1>&, iter_value_t<I2>&> && Relation<F&, iter_value_t<I1>&, iter_reference_t<I2>> && Relation<F&, iter_reference_t<I1>, iter_value_t<I2>&> && Relation<F&, iter_reference_t<I1>, iter_reference_t<I2>> && Relation<F&, iter_common_reference_t<I1>, iter_common_reference_t<I2>>; template<class F, class I1, class I2 = I1> concept IndirectStrictWeakOrder = Readable<I1> && Readable<I2> && CopyConstructible<F> && StrictWeakOrder<F&, iter_value_t<I1>&, iter_value_t<I2>&> && StrictWeakOrder<F&, iter_value_t<I1>&, iter_reference_t<I2>> && StrictWeakOrder<F&, iter_reference_t<I1>, iter_value_t<I2>&> && StrictWeakOrder<F&, iter_reference_t<I1>, iter_reference_t<I2>> && StrictWeakOrder<F&, iter_common_reference_t<I1>, iter_common_reference_t<I2>>; }
namespace std { template<Readable I, IndirectRegularUnaryInvocable<I> Proj> struct projected { using value_type = remove_cvref_t<indirect_result_t<Proj&, I>>; indirect_result_t<Proj&, I> operator*() const; // not defined }; template<WeaklyIncrementable I, class Proj> struct incrementable_traits<projected<I, Proj>> { using difference_type = iter_difference_t<I>; }; }
template<class In, class Out> concept IndirectlyMovable = Readable<In> && Writable<Out, iter_rvalue_reference_t<In>>;
template<class In, class Out> concept IndirectlyMovableStorable = IndirectlyMovable<In, Out> && Writable<Out, iter_value_t<In>> && Movable<iter_value_t<In>> && Constructible<iter_value_t<In>, iter_rvalue_reference_t<In>> && Assignable<iter_value_t<In>&, iter_rvalue_reference_t<In>>;
iter_value_t<In> obj(ranges::iter_move(i));obj is equal to the value previously denoted by *i.
template<class In, class Out> concept IndirectlyCopyable = Readable<In> && Writable<Out, iter_reference_t<In>>;
template<class In, class Out> concept IndirectlyCopyableStorable = IndirectlyCopyable<In, Out> && Writable<Out, const iter_value_t<In>&> && Copyable<iter_value_t<In>> && Constructible<iter_value_t<In>, iter_reference_t<In>> && Assignable<iter_value_t<In>&, iter_reference_t<In>>;
iter_value_t<In> obj(*i);obj is equal to the value previously denoted by *i.
template<class I1, class I2 = I1> concept IndirectlySwappable = Readable<I1> && Readable<I2> && requires(I1& i1, I2& i2) { ranges::iter_swap(i1, i1); ranges::iter_swap(i2, i2); ranges::iter_swap(i1, i2); ranges::iter_swap(i2, i1); };
template<class I1, class I2, class R, class P1 = identity, class P2 = identity> concept IndirectlyComparable = IndirectRelation<R, projected<I1, P1>, projected<I2, P2>>;
template<class I1, class I2, class Out, class R = ranges::less<>, class P1 = identity, class P2 = identity> concept Mergeable = InputIterator<I1> && InputIterator<I2> && WeaklyIncrementable<Out> && IndirectlyCopyable<I1, Out> && IndirectlyCopyable<I2, Out> && IndirectStrictWeakOrder<R, projected<I1, P1>, projected<I2, P2>>;