24 Ranges library [ranges]

24.1 General [ranges.general]

This clause describes components for dealing with ranges of elements.
The following subclauses describe range and view requirements, and components for range primitives as summarized in Table 90.
Table 90: Ranges library summary   [tab:range.summary]
Subclause
Header
Range access
<ranges>
Requirements
Range utilities
Range factories
Range adaptors

24.2 Header <ranges> synopsis [ranges.syn]

#include <compare>              // see [compare.syn]
#include <initializer_list>     // see [initializer.list.syn]
#include <iterator>             // see [iterator.synopsis]

namespace std::ranges {
  inline namespace unspecified {
    // [range.access], range access
    inline constexpr unspecified begin = unspecified;
    inline constexpr unspecified end = unspecified;
    inline constexpr unspecified cbegin = unspecified;
    inline constexpr unspecified cend = unspecified;
    inline constexpr unspecified rbegin = unspecified;
    inline constexpr unspecified rend = unspecified;
    inline constexpr unspecified crbegin = unspecified;
    inline constexpr unspecified crend = unspecified;

    inline constexpr unspecified size = unspecified;
    inline constexpr unspecified ssize = unspecified;
    inline constexpr unspecified empty = unspecified;
    inline constexpr unspecified data = unspecified;
    inline constexpr unspecified cdata = unspecified;
  }

  // [range.range], ranges
  template<class T>
    concept range = see below;

  template<class T>
    inline constexpr bool enable_borrowed_range = false;

  template<class T>
    concept borrowed_range = see below;

  template<class T>
    using iterator_t = decltype(ranges::begin(declval<T&>()));
  template<range R>
    using sentinel_t = decltype(ranges::end(declval<R&>()));
  template<range R>
    using range_difference_t = iter_difference_t<iterator_t<R>>;
  template<sized_range R>
    using range_size_t = decltype(ranges::size(declval<R&>()));
  template<range R>
    using range_value_t = iter_value_t<iterator_t<R>>;
  template<range R>
    using range_reference_t = iter_reference_t<iterator_t<R>>;
  template<range R>
    using range_rvalue_reference_t = iter_rvalue_reference_t<iterator_t<R>>;

  // [range.sized], sized ranges
  template<class>
    inline constexpr bool disable_sized_range = false;

  template<class T>
    concept sized_range = see below;

  // [range.view], views
  template<class T>
    inline constexpr bool enable_view = see below;

  struct view_base { };

  template<class T>
    concept view = see below;

  // [range.refinements], other range refinements
  template<class R, class T>
    concept output_range = see below;

  template<class T>
    concept input_range = see below;

  template<class T>
    concept forward_range = see below;

  template<class T>
    concept bidirectional_range = see below;

  template<class T>
    concept random_access_range = see below;

  template<class T>
    concept contiguous_range = see below;

  template<class T>
    concept common_range = see below;

  template<class T>
    concept viewable_range = see below;

  // [view.interface], class template view_­interface
  template<class D>
    requires is_class_v<D> && same_as<D, remove_cv_t<D>>
  class view_interface;

  // [range.subrange], sub-ranges
  enum class subrange_kind : bool { unsized, sized };

  template<input_or_output_iterator I, sentinel_for<I> S = I, subrange_kind K = see below>
    requires (K == subrange_kind::sized || !sized_sentinel_for<S, I>)
  class subrange;

  template<input_or_output_iterator I, sentinel_for<I> S, subrange_kind K>
    inline constexpr bool enable_borrowed_range<subrange<I, S, K>> = true;

  // [range.dangling], dangling iterator handling
  struct dangling;

  template<range R>
    using borrowed_iterator_t = conditional_t<borrowed_range<R>, iterator_t<R>, dangling>;

  template<range R>
    using borrowed_subrange_t =
      conditional_t<borrowed_range<R>, subrange<iterator_t<R>>, dangling>;

  // [range.empty], empty view
  template<class T>
    requires is_object_v<T>
  class empty_view;

  template<class T>
    inline constexpr bool enable_borrowed_range<empty_view<T>> = true;

  namespace views {
    template<class T>
      inline constexpr empty_view<T> empty{};
  }

  // [range.single], single view
  template<copy_constructible T>
    requires is_object_v<T>
  class single_view;

  namespace views { inline constexpr unspecified single = unspecified; }

  // [range.iota], iota view
  template<weakly_incrementable W, semiregular Bound = unreachable_sentinel_t>
    requires weakly-equality-comparable-with<W, Bound>
  class iota_view;

  template<weakly_incrementable W, semiregular Bound>
    inline constexpr bool enable_borrowed_range<iota_view<W, Bound>> = true;

  namespace views { inline constexpr unspecified iota = unspecified; }

  // [range.istream], istream view
  template<movable Val, class CharT, class Traits = char_traits<CharT>>
    requires see below
  class basic_istream_view;
  template<class Val, class CharT, class Traits>
    basic_istream_view<Val, CharT, Traits> istream_view(basic_istream<CharT, Traits>& s);

  // [range.all], all view
  namespace views {
    inline constexpr unspecified all = unspecified;

    template<viewable_range R>
      using all_t = decltype(all(declval<R>()));
  }

  template<range R>
    requires is_object_v<R>
  class ref_view;

  template<class T>
    inline constexpr bool enable_borrowed_range<ref_view<T>> = true;

  // [range.filter], filter view
  template<input_range V, indirect_unary_predicate<iterator_t<V>> Pred>
    requires view<V> && is_object_v<Pred>
  class filter_view;

  namespace views { inline constexpr unspecified filter = unspecified; }

  // [range.transform], transform view
  template<input_range V, copy_constructible F>
    requires view<V> && is_object_v<F> &&
             regular_invocable<F&, range_reference_t<V>>
  class transform_view;

  namespace views { inline constexpr unspecified transform = unspecified; }

  // [range.take], take view
  template<view> class take_view;

  namespace views { inline constexpr unspecified take = unspecified; }

  // [range.take.while], take while view
  template<view V, class Pred>
    requires input_range<V> && is_object_v<Pred> &&
             indirect_unary_predicate<const Pred, iterator_t<V>>
    class take_while_view;

  namespace views { inline constexpr unspecified take_while = unspecified; }

  // [range.drop], drop view
  template<view V>
    class drop_view;

  namespace views { inline constexpr unspecified drop = unspecified; }

  // [range.drop.while], drop while view
  template<view V, class Pred>
    requires input_range<V> && is_object_v<Pred> &&
             indirect_unary_predicate<const Pred, iterator_t<V>>
    class drop_while_view;

  namespace views { inline constexpr unspecified drop_while = unspecified; }

  // [range.join], join view
  template<input_range V>
    requires view<V> && input_range<range_reference_t<V>> &&
             (is_reference_v<range_reference_t<V>> ||
              view<range_value_t<V>>)
  class join_view;

  namespace views { inline constexpr unspecified join = unspecified; }

  // [range.split], split view
  template<class R>
    concept tiny-range = see below;   // exposition only

  template<input_range V, forward_range Pattern>
    requires view<V> && view<Pattern> &&
             indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
             (forward_range<V> || tiny-range<Pattern>)
  class split_view;

  namespace views { inline constexpr unspecified split = unspecified; }

  // [range.counted], counted view
  namespace views { inline constexpr unspecified counted = unspecified; }

  // [range.common], common view
  template<view V>
    requires (!common_range<V> && copyable<iterator_t<V>>)
  class common_view;

  namespace views { inline constexpr unspecified common = unspecified; }

  // [range.reverse], reverse view
  template<view V>
    requires bidirectional_range<V>
  class reverse_view;

  namespace views { inline constexpr unspecified reverse = unspecified; }

  // [range.elements], elements view
  template<input_range V, size_t N>
    requires see below;
  class elements_view;

  template<class R>
    using keys_view = elements_view<views::all_t<R>, 0>;
  template<class R>
    using values_view = elements_view<views::all_t<R>, 1>;

  namespace views {
    template<size_t N>
      inline constexpr unspecified elements = unspecified ;
    inline constexpr auto keys = elements<0>;
    inline constexpr auto values = elements<1>;
  }
}

namespace std {
  namespace views = ranges::views;

  template<class I, class S, ranges::subrange_kind K>
  struct tuple_size<ranges::subrange<I, S, K>>
    : integral_constant<size_t, 2> {};
  template<class I, class S, ranges::subrange_kind K>
  struct tuple_element<0, ranges::subrange<I, S, K>> {
    using type = I;
  };
  template<class I, class S, ranges::subrange_kind K>
  struct tuple_element<1, ranges::subrange<I, S, K>> {
    using type = S;
  };
  template<class I, class S, ranges::subrange_kind K>
  struct tuple_element<0, const ranges::subrange<I, S, K>> {
    using type = I;
  };
  template<class I, class S, ranges::subrange_kind K>
  struct tuple_element<1, const ranges::subrange<I, S, K>> {
    using type = S;
  };
}
Within this clause, for an integer-like type X ([iterator.concept.winc]), make-unsigned-like-t<X> denotes make_­unsigned_­t<X> if X is an integer type; otherwise, it denotes a corresponding unspecified unsigned-integer-like type of the same width as X.
For an expression x of type X, to-unsigned-like(x) is x explicitly converted to make-unsigned-like-t<X>.

24.3 Range access [range.access]

In addition to being available via inclusion of the <ranges> header, the customization point objects in [range.access] are available when <iterator> ([iterator.synopsis]) is included.
Within this subclause, the reified object of a subexpression E denotes
  • the same object as E if E is a glvalue, or
  • the result of applying the temporary materialization conversion ([conv.rval]) to E otherwise.

24.3.1 ranges​::​begin [range.access.begin]

The name ranges​::​begin denotes a customization point object ([customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If E is an rvalue and enable_­borrowed_­range<remove_­cv_­t<T>> is false, ranges​::​begin(E) is ill-formed.
  • Otherwise, if T is an array type ([basic.compound]) and remove_­all_­extents_­t<T> is an incomplete type, ranges​::​begin(E) is ill-formed with no diagnostic required.
  • Otherwise, if T is an array type, ranges​::​begin(E) is expression-equivalent to t + 0.
  • Otherwise, if decay-copy(t.begin()) is a valid expression whose type models input_­or_­output_­iterator, ranges​::​begin(E) is expression-equivalent to decay-copy(t.begin()).
  • Otherwise, if T is a class or enumeration type and decay-copy(begin(t)) is a valid expression whose type models input_­or_­output_­iterator with overload resolution performed in a context in which unqualified lookup for begin finds only the declarations
    void begin(auto&) = delete;
    void begin(const auto&) = delete;
    
    then ranges​::​begin(E) is expression-equivalent to decay-copy(begin(t)) with overload resolution performed in the above context.
  • Otherwise, ranges​::​begin(E) is ill-formed.
Note
:
Diagnosable ill-formed cases above result in substitution failure when ranges​::​begin(E) appears in the immediate context of a template instantiation.
— end note
 ]
Note
:
Whenever ranges​::​begin(E) is a valid expression, its type models input_­or_­output_­iterator.
— end note
 ]

24.3.2 ranges​::​end [range.access.end]

The name ranges​::​end denotes a customization point object ([customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If E is an rvalue and enable_­borrowed_­range<remove_­cv_­t<T>> is false, ranges​::​end(E) is ill-formed.
  • Otherwise, if T is an array type ([basic.compound]) and remove_­all_­extents_­t<T> is an incomplete type, ranges​::​end(E) is ill-formed with no diagnostic required.
  • Otherwise, if T is an array of unknown bound, ranges​::​end(E) is ill-formed.
  • Otherwise, if T is an array, ranges​::​end(E) is expression-equivalent to t + extent_­v<T>.
  • Otherwise, if decay-copy(t.end()) is a valid expression whose type models sentinel_­for<iterator_­t<T>> then ranges​::​end(E) is expression-equivalent to decay-copy(t.end()).
  • Otherwise, if T is a class or enumeration type and decay-copy(end(t)) is a valid expression whose type models sentinel_­for<iterator_­t<T>> with overload resolution performed in a context in which unqualified lookup for end finds only the declarations
    void end(auto&) = delete;
    void end(const auto&) = delete;
    
    then ranges​::​end(E) is expression-equivalent to decay-copy(end(t)) with overload resolution performed in the above context.
  • Otherwise, ranges​::​end(E) is ill-formed.
Note
:
Diagnosable ill-formed cases above result in substitution failure when ranges​::​end(E) appears in the immediate context of a template instantiation.
— end note
 ]
Note
:
Whenever ranges​::​end(E) is a valid expression, the types S and I of ranges​::​end(E) and ranges​::​begin(E) model sentinel_­for<S, I>.
— end note
 ]

24.3.3 ranges​::​cbegin [range.access.cbegin]

The name ranges​::​cbegin denotes a customization point object ([customization.point.object]).
The expression ranges​::​​cbegin(E) for a subexpression E of type T is expression-equivalent to:
  • ranges​::​begin(static_­cast<const T&>(E)) if E is an lvalue.
  • Otherwise, ranges​::​begin(static_­cast<const T&&>(E)).
Note
:
Whenever ranges​::​cbegin(E) is a valid expression, its type models input_­or_­output_­iterator.
— end note
 ]

24.3.4 ranges​::​cend [range.access.cend]

The name ranges​::​cend denotes a customization point object ([customization.point.object]).
The expression ranges​::​cend(E) for a subexpression E of type T is expression-equivalent to:
  • ranges​::​end(static_­cast<const T&>(E)) if E is an lvalue.
  • Otherwise, ranges​::​end(static_­cast<const T&&>(E)).
Note
:
Whenever ranges​::​cend(E) is a valid expression, the types S and I of ranges​::​cend(E) and ranges​::​cbegin(E) model sentinel_­for<S, I>.
— end note
 ]

24.3.5 ranges​::​rbegin [range.access.rbegin]

The name ranges​::​rbegin denotes a customization point object ([customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If E is an rvalue and enable_­borrowed_­range<remove_­cv_­t<T>> is false, ranges​::​rbegin(E) is ill-formed.
  • Otherwise, if T is an array type ([basic.compound]) and remove_­all_­extents_­t<T> is an incomplete type, ranges​::​rbegin(E) is ill-formed with no diagnostic required.
  • Otherwise, if decay-copy(t.rbegin()) is a valid expression whose type models input_­or_­output_­iterator, ranges​::​rbegin(E) is expression-equivalent to decay-copy(t.rbegin()).
  • Otherwise, if T is a class or enumeration type and decay-copy(rbegin(t)) is a valid expression whose type models input_­or_­output_­iterator with overload resolution performed in a context in which unqualified lookup for rbegin finds only the declarations
    void rbegin(auto&) = delete;
    void rbegin(const auto&) = delete;
    
    then ranges​::​rbegin(E) is expression-equivalent to decay-copy(rbegin(t)) with overload resolution performed in the above context.
  • Otherwise, if both ranges​::​begin(t) and ranges​::​end(t) are valid expressions of the same type which models bidirectional_­iterator ([iterator.concept.bidir]), ranges​::​rbegin(E) is expression-equivalent to make_­reverse_­iterator(ranges​::​end(t)).
  • Otherwise, ranges​::​rbegin(E) is ill-formed.
Note
:
Diagnosable ill-formed cases above result in substitution failure when ranges​::​rbegin(E) appears in the immediate context of a template instantiation.
— end note
 ]
Note
:
Whenever ranges​::​rbegin(E) is a valid expression, its type models input_­or_­output_­iterator.
— end note
 ]

24.3.6 ranges​::​rend [range.access.rend]

The name ranges​::​rend denotes a customization point object ([customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If E is an rvalue and enable_­borrowed_­range<remove_­cv_­t<T>> is false, ranges​::​rend(E) is ill-formed.
  • Otherwise, if T is an array type ([basic.compound]) and remove_­all_­extents_­t<T> is an incomplete type, ranges​::​rend(E) is ill-formed with no diagnostic required.
  • Otherwise, if decay-copy(t.rend()) is a valid expression whose type models sentinel_­for<decltype(ranges​::​rbegin(E))> then ranges​::​rend(E) is expression-equivalent to decay-copy(t.rend()).
  • Otherwise, if T is a class or enumeration type and decay-copy(rend(t)) is a valid expression whose type models sentinel_­for<decltype(ranges​::​rbegin(E))> with overload resolution performed in a context in which unqualified lookup for rend finds only the declarations
    void rend(auto&) = delete;
    void rend(const auto&) = delete;
    
    then ranges​::​rend(E) is expression-equivalent to decay-copy(rend(t)) with overload resolution performed in the above context.
  • Otherwise, if both ranges​::​begin(t) and ranges​::​end(t) are valid expressions of the same type which models bidirectional_­iterator ([iterator.concept.bidir]), then ranges​::​rend(E) is expression-equivalent to make_­reverse_­iterator(ranges​::​begin(t)).
  • Otherwise, ranges​::​rend(E) is ill-formed.
Note
:
Diagnosable ill-formed cases above result in substitution failure when ranges​::​rend(E) appears in the immediate context of a template instantiation.
— end note
 ]
Note
:
Whenever ranges​::​rend(E) is a valid expression, the types S and I of ranges​::​rend(E) and ranges​::​rbegin(E) model sentinel_­for<S, I>.
— end note
 ]

24.3.7 ranges​::​crbegin [range.access.crbegin]

The name ranges​::​crbegin denotes a customization point object ([customization.point.object]).
The expression ranges​::​​crbegin(E) for a subexpression E of type T is expression-equivalent to:
  • ranges​::​​rbegin(static_­cast<const T&>(E)) if E is an lvalue.
  • Otherwise, ranges​::​rbegin(static_­cast<const T&&>(E)).
Note
:
Whenever ranges​::​crbegin(E) is a valid expression, its type models input_­or_­output_­iterator.
— end note
 ]

24.3.8 ranges​::​crend [range.access.crend]

The name ranges​::​crend denotes a customization point object ([customization.point.object]).
The expression ranges​::​​crend(E) for a subexpression E of type T is expression-equivalent to:
  • ranges​::​rend(static_­cast<const T&>(E)) if E is an lvalue.
  • Otherwise, ranges​::​rend(static_­cast<const T&&>(E)).
Note
:
Whenever ranges​::​crend(E) is a valid expression, the types S and I of ranges​::​crend(E) and ranges​::​crbegin(E) model sentinel_­for<S, I>.
— end note
 ]

24.3.9 ranges​::​size [range.prim.size]

The name ranges​::​size denotes a customization point object ([customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If T is an array of unknown bound ([dcl.array]), ranges​::​size(E) is ill-formed.
  • Otherwise, if T is an array type, ranges​::​size(E) is expression-equivalent to decay-copy(extent_­v<T>).
  • Otherwise, if disable_­sized_­range<remove_­cv_­t<T>> ([range.sized]) is false and decay-copy(t.size()) is a valid expression of integer-like type ([iterator.concept.winc]), ranges​::​size(E) is expression-equivalent to decay-copy(t.size()).
  • Otherwise, if T is a class or enumeration type, disable_­sized_­range<remove_­cv_­t<T>> is false and decay-copy(size(t)) is a valid expression of integer-like type with overload resolution performed in a context in which unqualified lookup for size finds only the declarations
    void size(auto&) = delete;
    void size(const auto&) = delete;
    
    then ranges​::​size(E) is expression-equivalent to decay-copy(size(t)) with overload resolution performed in the above context.
  • Otherwise, if to-unsigned-like(ranges​::​end(t) - ranges​::​begin(t)) ([ranges.syn]) is a valid expression and the types I and S of ranges​::​begin(t) and ranges​::​end(t) (respectively) model both sized_­sentinel_­for<S, I> ([iterator.concept.sizedsentinel]) and forward_­iterator<I>, then ranges​::​size(E) is expression-equivalent to to-unsigned-like(ranges​::​end(t) - ranges​::​begin(t)).
  • Otherwise, ranges​::​size(E) is ill-formed.
Note
:
Diagnosable ill-formed cases above result in substitution failure when ranges​::​size(E) appears in the immediate context of a template instantiation.
— end note
 ]
Note
:
Whenever ranges​::​size(E) is a valid expression, its type is integer-like.
— end note
 ]

24.3.10 ranges​::​ssize [range.prim.ssize]

The name ranges​::​ssize denotes a customization point object ([customization.point.object]).
The expression ranges​::​ssize(​E) for a subexpression E of type T is expression-equivalent to:
  • If range_­difference_­t<T> has width less than ptrdiff_­t, static_­cast<ptrdiff_­t>(ranges​::​
    size(E))
    .
  • Otherwise, static_­cast<range_­difference_­t<T>>(ranges​::​size(E)).

24.3.11 ranges​::​empty [range.prim.empty]

The name ranges​::​empty denotes a customization point object ([customization.point.object]).
Given a subexpression ranges​::​empty(E) with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If T is an array of unknown bound ([basic.compound]), ranges​::​empty(E) is ill-formed.
  • Otherwise, if bool(t.empty()) is a valid expression, ranges​::​empty(E) is expression-equivalent to bool(t.empty()).
  • Otherwise, if (ranges​::​size(t) == 0) is a valid expression, ranges​::​empty(E) is expression-equivalent to (ranges​::​size(t) == 0).
  • Otherwise, if bool(ranges​::​begin(t) == ranges​::​end(t)) is a valid expression and the type of ranges​::​begin(t) models forward_­iterator, ranges​::​empty(E) is expression-equivalent to bool(​ranges​::​begin(t) == ranges​::​end(t)).
  • Otherwise, ranges​::​empty(E) is ill-formed.
Note
:
Diagnosable ill-formed cases above result in substitution failure when ranges​::​empty(E) appears in the immediate context of a template instantiation.
— end note
 ]
Note
:
Whenever ranges​::​empty(E) is a valid expression, it has type bool.
— end note
 ]

24.3.12 ranges​::​data [range.prim.data]

The name ranges​::​data denotes a customization point object ([customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If E is an rvalue and enable_­borrowed_­range<remove_­cv_­t<T>> is false, ranges​::​data(E) is ill-formed.
  • Otherwise, if T is an array type ([basic.compound]) and remove_­all_­extents_­t<T> is an incomplete type, ranges​::​data(E) is ill-formed with no diagnostic required.
  • Otherwise, if decay-copy(t.data()) is a valid expression of pointer to object type, ranges​::​data(E) is expression-equivalent to decay-copy(t.data()).
  • Otherwise, if ranges​::​begin(t) is a valid expression whose type models contiguous_­iterator, ranges​::​data(E) is expression-equivalent to to_­address(ranges​::​begin(E)).
  • Otherwise, ranges​::​data(E) is ill-formed.
Note
:
Diagnosable ill-formed cases above result in substitution failure when ranges​::​data(E) appears in the immediate context of a template instantiation.
— end note
 ]
Note
:
Whenever ranges​::​data(E) is a valid expression, it has pointer to object type.
— end note
 ]

24.3.13 ranges​::​cdata [range.prim.cdata]

The name ranges​::​cdata denotes a customization point object ([customization.point.object]).
The expression ranges​::​​cdata(E) for a subexpression E of type T is expression-equivalent to:
  • ranges​::​data(static_­cast<const T&>(E)) if E is an lvalue.
  • Otherwise, ranges​::​data(static_­cast<const T&&>(E)).
Note
:
Whenever ranges​::​cdata(E) is a valid expression, it has pointer to object type.
— end note
 ]

24.4 Range requirements [range.req]

24.4.1 General [range.req.general]

Ranges are an abstraction that allow a C++ program to operate on elements of data structures uniformly.
Calling ranges​::​begin on a range returns an object whose type models input_­or_­output_­iterator ([iterator.concept.iterator]).
Calling ranges​::​end on a range returns an object whose type S, together with the type I of the object returned by ranges​::​begin, models sentinel_­for<S, I>.
The library formalizes the interfaces, semantics, and complexity of ranges to enable algorithms and range adaptors that work efficiently on different types of sequences.
The range concept requires that ranges​::​begin and ranges​::​end return an iterator and a sentinel, respectively.
The sized_­range concept refines range with the requirement that ranges​::​size be amortized .
The view concept specifies requirements on a range type with constant-time destruction and move operations.
Several refinements of range group requirements that arise frequently in concepts and algorithms.
Common ranges are ranges for which ranges​::​begin and ranges​::​end return objects of the same type.
Random access ranges are ranges for which ranges​::​begin returns a type that models random_­access_­iterator ([iterator.concept.random.access]).
(Contiguous, bidirectional, forward, input, and output ranges are defined similarly.)
Viewable ranges can be converted to views.

24.4.2 Ranges [range.range]

The range concept defines the requirements of a type that allows iteration over its elements by providing an iterator and sentinel that denote the elements of the range.
template<class T> concept range = requires(T& t) { ranges::begin(t); // sometimes equality-preserving (see below) ranges::end(t); };
The required expressions ranges​::​begin(t) and ranges​::​end(t) of the range concept do not require implicit expression variations ([concepts.equality]).
Given an expression t such that decltype((t)) is T&, T models range only if
  • [ranges​::​begin(t), ranges​::​end(t)) denotes a range ([iterator.requirements.general]),
  • both ranges​::​begin(t) and ranges​::​end(t) are amortized constant time and non-modifying, and
  • if the type of ranges​::​begin(t) models forward_­iterator, ranges​::​begin(t) is equality-preserving.
Note
:
Equality preservation of both ranges​::​begin and ranges​::​end enables passing a range whose iterator type models forward_­iterator to multiple algorithms and making multiple passes over the range by repeated calls to ranges​::​begin and ranges​::​end.
Since ranges​::​begin is not required to be equality-preserving when the return type does not model forward_­iterator, repeated calls might not return equal values or might not be well-defined; ranges​::​begin should be called at most once for such a range.
— end note
 ]
template<class T> concept borrowed_­range = range<T> && (is_lvalue_reference_v<T> || enable_borrowed_range<remove_cvref_t<T>>);
Given an expression E such that decltype((E)) is T, T models borrowed_­range only if the validity of iterators obtained from the object denoted by E is not tied to the lifetime of that object.
Note
:
Since the validity of iterators is not tied to the lifetime of an object whose type models borrowed_­range, a function can accept arguments of such a type by value and return iterators obtained from it without danger of dangling.
— end note
 ]
template<class> inline constexpr bool enable_borrowed_range = false;
Remarks: Pursuant to [namespace.std], users may specialize enable_­borrowed_­range for cv-unqualified program-defined types.
Such specializations shall be usable in constant expressions ([expr.const]) and have type const bool.
Example
:
Each specialization S of class template subrange ([range.subrange]) models borrowed_­range because
  • enable_­borrowed_­range<S> is specialized to have the value true, and
  • S's iterators do not have validity tied to the lifetime of an S object because they are “borrowed” from some other range.
— end example
 ]

24.4.3 Sized ranges [range.sized]

The sized_­range concept refines range with the requirement that the number of elements in the range can be determined in amortized constant time using ranges​::​size.
template<class T> concept sized_­range = range<T> && requires(T& t) { ranges::size(t); };
Given an lvalue t of type remove_­reference_­t<T>, T models sized_­range only if
  • ranges​::​size(t) is amortized , does not modify t, and is equal to ranges​::​distance(t), and
  • if iterator_­t<T> models forward_­iterator, ranges​::​size(t) is well-defined regardless of the evaluation of ranges​::​begin(t).
    Note
    : ranges​::​size(t) is otherwise not required to be well-defined after evaluating ranges​::​begin(t). For example, ranges​::​size(t) might be well-defined for a sized_­range whose iterator type does not model forward_­iterator only if evaluated before the first call to ranges​::​begin(t). — end note
     ]
template<class> inline constexpr bool disable_sized_range = false;
Remarks: Pursuant to [namespace.std], users may specialize disable_­sized_­range for cv-unqualified program-defined types.
Such specializations shall be usable in constant expressions ([expr.const]) and have type const bool.
Note
:
disable_­sized_­range allows use of range types with the library that satisfy but do not in fact model sized_­range.
— end note
 ]

24.4.4 Views [range.view]

The view concept specifies the requirements of a range type that has constant time move construction, move assignment, and destruction; that is, the cost of these operations is independent of the number of elements in the view.
template<class T> concept view = range<T> && movable<T> && default_­initializable<T> && enable_view<T>;
T models view only if:
  • T has move construction; and
  • T has move assignment; and
  • T has destruction; and
  • copy_­constructible<T> is false, or T has copy construction; and
  • copyable<T> is false, or T has copy assignment.
Example
:
Examples of views are:
  • A range type that wraps a pair of iterators.
  • A range type that holds its elements by shared_­ptr and shares ownership with all its copies.
  • A range type that generates its elements on demand.
Most containers are not views since destruction of the container destroys the elements, which cannot be done in constant time.
— end example
 ]
Since the difference between range and view is largely semantic, the two are differentiated with the help of enable_­view.
template<class T> inline constexpr bool enable_view = derived_from<T, view_base>;
Remarks: Pursuant to [namespace.std], users may specialize enable_­view to true for cv-unqualified program-defined types which model view, and false for types which do not.
Such specializations shall be usable in constant expressions ([expr.const]) and have type const bool.

24.4.5 Other range refinements [range.refinements]

The output_­range concept specifies requirements of a range type for which ranges​::​begin returns a model of output_­iterator ([iterator.concept.output]).
input_­range, forward_­range, bidirectional_­range, and random_­access_­range are defined similarly.
template<class R, class T> concept output_­range = range<R> && output_­iterator<iterator_t<R>, T>; template<class T> concept input_­range = range<T> && input_­iterator<iterator_t<T>>; template<class T> concept forward_­range = input_­range<T> && forward_­iterator<iterator_t<T>>; template<class T> concept bidirectional_­range = forward_­range<T> && bidirectional_­iterator<iterator_t<T>>; template<class T> concept random_­access_­range = bidirectional_­range<T> && random_­access_­iterator<iterator_t<T>>;
contiguous_­range additionally requires that the ranges​::​data customization point ([range.prim.data]) is usable with the range.
template<class T> concept contiguous_­range = random_­access_­range<T> && contiguous_iterator<iterator_t<T>> && requires(T& t) { { ranges::data(t) } -> same_­as<add_pointer_t<range_reference_t<T>>>; };
Given an expression t such that decltype((t)) is T&, T models contiguous_­range only if to_­address(​ranges​::​begin(t)) == ranges​::​data(t) is true.
The common_­range concept specifies requirements of a range type for which ranges​::​begin and ranges​::​end return objects of the same type.
Example
:
The standard containers ([containers]) model common_­range.
— end example
 ]
template<class T> concept common_­range = range<T> && same_­as<iterator_t<T>, sentinel_t<T>>;
The viewable_­range concept specifies the requirements of a range type that can be converted to a view safely.
template<class T> concept viewable_­range = range<T> && (borrowed_range<T> || view<remove_cvref_t<T>>);

24.5 Range utilities [range.utility]

The components in this subclause are general utilities for representing and manipulating ranges.

24.5.1 Helper concepts [range.utility.helpers]

Many of the types in subclause [range.utility] are specified in terms of the following exposition-only concepts:
template<class R>
  concept simple-view =                         // exposition only
    view<R> && range<const R> &&
    same_as<iterator_t<R>, iterator_t<const R>> &&
    same_as<sentinel_t<R>, sentinel_t<const R>>;

template<class I>
  concept has-arrow =                           // exposition only
    input_iterator<I> && (is_pointer_v<I> || requires(I i) { i.operator->(); });

template<class T, class U>
  concept not-same-as =                         // exposition only
    !same_as<remove_cvref_t<T>, remove_cvref_t<U>>;

24.5.2 View interface [view.interface]

The class template view_­interface is a helper for defining view-like types that offer a container-like interface.
It is parameterized with the type that is derived from it.
namespace std::ranges {
  template<class D>
    requires is_class_v<D> && same_as<D, remove_cv_t<D>>
  class view_interface : public view_base {
  private:
    constexpr D& derived() noexcept {                   // exposition only
      return static_cast<D&>(*this);
    }
    constexpr const D& derived() const noexcept {       // exposition only
      return static_cast<const D&>(*this);
    }
  public:
    constexpr bool empty() requires forward_range<D> {
      return ranges::begin(derived()) == ranges::end(derived());
    }
    constexpr bool empty() const requires forward_range<const D> {
      return ranges::begin(derived()) == ranges::end(derived());
    }

    constexpr explicit operator bool()
      requires requires { ranges::empty(derived()); } {
        return !ranges::empty(derived());
      }
    constexpr explicit operator bool() const
      requires requires { ranges::empty(derived()); } {
        return !ranges::empty(derived());
      }

    constexpr auto data() requires contiguous_iterator<iterator_t<D>> {
      return to_address(ranges::begin(derived()));
    }
    constexpr auto data() const
      requires range<const D> && contiguous_iterator<iterator_t<const D>> {
        return to_address(ranges::begin(derived()));
      }

    constexpr auto size() requires forward_range<D> &&
      sized_sentinel_for<sentinel_t<D>, iterator_t<D>> {
        return ranges::end(derived()) - ranges::begin(derived());
      }
    constexpr auto size() const requires forward_range<const D> &&
      sized_sentinel_for<sentinel_t<const D>, iterator_t<const D>> {
        return ranges::end(derived()) - ranges::begin(derived());
      }

    constexpr decltype(auto) front() requires forward_range<D>;
    constexpr decltype(auto) front() const requires forward_range<const D>;

    constexpr decltype(auto) back() requires bidirectional_range<D> && common_range<D>;
    constexpr decltype(auto) back() const
      requires bidirectional_range<const D> && common_range<const D>;

    template<random_access_range R = D>
      constexpr decltype(auto) operator[](range_difference_t<R> n) {
        return ranges::begin(derived())[n];
      }
    template<random_access_range R = const D>
      constexpr decltype(auto) operator[](range_difference_t<R> n) const {
        return ranges::begin(derived())[n];
      }
  };
}
The template parameter D for view_­interface may be an incomplete type.
Before any member of the resulting specialization of view_­interface other than special member functions is referenced, D shall be complete, and model both derived_­from<view_­interface<D>> and view.

24.5.2.1 Members [view.interface.members]

constexpr decltype(auto) front() requires forward_­range<D>; constexpr decltype(auto) front() const requires forward_­range<const D>;
Preconditions: !empty().
Effects: Equivalent to: return *ranges​::​begin(derived());
constexpr decltype(auto) back() requires bidirectional_­range<D> && common_range<D>; constexpr decltype(auto) back() const requires bidirectional_­range<const D> && common_range<const D>;
Preconditions: !empty().
Effects: Equivalent to: return *ranges​::​prev(ranges​::​end(derived()));

24.5.3 Sub-ranges [range.subrange]

The subrange class template combines together an iterator and a sentinel into a single object that models the view concept.
Additionally, it models the sized_­range concept when the final template parameter is subrange_­kind​::​sized.
namespace std::ranges {
  template<class From, class To>
    concept convertible-to-non-slicing =                    // exposition only
      convertible_to<From, To> &&
      !(is_pointer_v<decay_t<From>> &&
        is_pointer_v<decay_t<To>> &&
        not-same-as<remove_pointer_t<decay_t<From>>, remove_pointer_t<decay_t<To>>>);

  template<class T>
    concept pair-like =                                     // exposition only
      !is_reference_v<T> && requires(T t) {
        typename tuple_size<T>::type;                       // ensures tuple_­size<T> is complete
        requires derived_from<tuple_size<T>, integral_constant<size_t, 2>>;
        typename tuple_element_t<0, remove_const_t<T>>;
        typename tuple_element_t<1, remove_const_t<T>>;
        { get<0>(t) } -> convertible_to<const tuple_element_t<0, T>&>;
        { get<1>(t) } -> convertible_to<const tuple_element_t<1, T>&>;
      };

  template<class T, class U, class V>
    concept pair-like-convertible-from =                    // exposition only
      !range<T> && pair-like<T> &&
      constructible_from<T, U, V> &&
      convertible-to-non-slicing<U, tuple_element_t<0, T>> &&
      convertible_to<V, tuple_element_t<1, T>>;

  template<class T>
    concept iterator-sentinel-pair =                        // exposition only
      !range<T> && pair-like<T> &&
      sentinel_for<tuple_element_t<1, T>, tuple_element_t<0, T>>;

  template<input_or_output_iterator I, sentinel_for<I> S = I, subrange_kind K =
      sized_sentinel_for<S, I> ? subrange_kind::sized : subrange_kind::unsized>
    requires (K == subrange_kind::sized || !sized_sentinel_for<S, I>)
  class subrange : public view_interface<subrange<I, S, K>> {
  private:
    static constexpr bool StoreSize =                           // exposition only
      K == subrange_kind::sized && !sized_sentinel_for<S, I>;
    I begin_ = I();                                             // exposition only
    S end_ = S();                                               // exposition only
    make-unsigned-like-t<iter_difference_t<I>> size_ = 0;       // exposition only; present only
                                                                // when StoreSize is true
  public:
    subrange() = default;

    constexpr subrange(convertible-to-non-slicing<I> auto i, S s) requires (!StoreSize);

    constexpr subrange(convertible-to-non-slicing<I> auto i, S s,
                       make-unsigned-like-t<iter_difference_t<I>> n)
      requires (K == subrange_kind::sized);

    template<not-same-as<subrange> R>
      requires borrowed_range<R> &&
               convertible-to-non-slicing<iterator_t<R>, I> &&
               convertible_to<sentinel_t<R>, S>
    constexpr subrange(R&& r) requires (!StoreSize || sized_range<R>);

    template<borrowed_range R>
      requires convertible-to-non-slicing<iterator_t<R>, I> &&
               convertible_to<sentinel_t<R>, S>
    constexpr subrange(R&& r, make-unsigned-like-t<iter_difference_t<I>> n)
      requires (K == subrange_kind::sized)
        : subrange{ranges::begin(r), ranges::end(r), n}
    {}

    template<not-same-as<subrange> PairLike>
      requires pair-like-convertible-from<PairLike, const I&, const S&>
    constexpr operator PairLike() const;

    constexpr I begin() const requires copyable<I>;
    [[nodiscard]] constexpr I begin() requires (!copyable<I>);
    constexpr S end() const;

    constexpr bool empty() const;
    constexpr make-unsigned-like-t<iter_difference_t<I>> size() const
      requires (K == subrange_kind::sized);

    [[nodiscard]] constexpr subrange next(iter_difference_t<I> n = 1) const &
      requires forward_iterator<I>;
    [[nodiscard]] constexpr subrange next(iter_difference_t<I> n = 1) &&;
    [[nodiscard]] constexpr subrange prev(iter_difference_t<I> n = 1) const
      requires bidirectional_iterator<I>;
    constexpr subrange& advance(iter_difference_t<I> n);
  };

  template<input_or_output_iterator I, sentinel_for<I> S>
    subrange(I, S) -> subrange<I, S>;

  template<input_or_output_iterator I, sentinel_for<I> S>
    subrange(I, S, make-unsigned-like-t<iter_difference_t<I>>) ->
      subrange<I, S, subrange_kind::sized>;

  template<iterator-sentinel-pair P>
    subrange(P) -> subrange<tuple_element_t<0, P>, tuple_element_t<1, P>>;

  template<iterator-sentinel-pair P>
    subrange(P, make-unsigned-like-t<iter_difference_t<tuple_element_t<0, P>>>) ->
      subrange<tuple_element_t<0, P>, tuple_element_t<1, P>, subrange_kind::sized>;

  template<borrowed_range R>
    subrange(R&&) ->
      subrange<iterator_t<R>, sentinel_t<R>,
               (sized_range<R> || sized_sentinel_for<sentinel_t<R>, iterator_t<R>>)
                 ? subrange_kind::sized : subrange_kind::unsized>;

  template<borrowed_range R>
    subrange(R&&, make-unsigned-like-t<range_difference_t<R>>) ->
      subrange<iterator_t<R>, sentinel_t<R>, subrange_kind::sized>;

  template<size_t N, class I, class S, subrange_kind K>
    requires (N < 2)
    constexpr auto get(const subrange<I, S, K>& r);

  template<size_t N, class I, class S, subrange_kind K>
    requires (N < 2)
    constexpr auto get(subrange<I, S, K>&& r);
}

namespace std {
  using ranges::get;
}

24.5.3.1 Constructors and conversions [range.subrange.ctor]

constexpr subrange(convertible-to-non-slicing<I> auto i, S s) requires (!StoreSize);
Preconditions: [i, s) is a valid range.
Effects: Initializes begin_­ with std​::​move(i) and end_­ with s.
constexpr subrange(convertible-to-non-slicing<I> auto i, S s, make-unsigned-like-t<iter_difference_t<I>> n) requires (K == subrange_kind::sized);
Preconditions: [i, s) is a valid range, and n == to-unsigned-like(ranges​::​distance(i, s)).
Effects: Initializes begin_­ with std​::​move(i) and end_­ with s.
If StoreSize is true, initializes size_­ with n.
Note
:
Accepting the length of the range and storing it to later return from size() enables subrange to model sized_­range even when it stores an iterator and sentinel that do not model sized_­sentinel_­for.
— end note
 ]
template<not-same-as<subrange> R> requires borrowed_­range<R> && convertible-to-non-slicing<iterator_t<R>, I> && convertible_­to<sentinel_t<R>, S> constexpr subrange(R&& r) requires (!StoreSize || sized_­range<R>);
Effects: Equivalent to:
  • If StoreSize is true, subrange{r, ranges​::​size(r)}.
  • Otherwise, subrange{ranges​::​begin(r), ranges​::​end(r)}.
template<not-same-as<subrange> PairLike> requires pair-like-convertible-from<PairLike, const I&, const S&> constexpr operator PairLike() const;
Effects: Equivalent to: return PairLike(begin_­, end_­);

24.5.3.2 Accessors [range.subrange.access]

constexpr I begin() const requires copyable<I>;
Effects: Equivalent to: return begin_­;
[[nodiscard]] constexpr I begin() requires (!copyable<I>);
Effects: Equivalent to: return std​::​move(begin_­);
constexpr S end() const;
Effects: Equivalent to: return end_­;
constexpr bool empty() const;
Effects: Equivalent to: return begin_­ == end_­;
constexpr make-unsigned-like-t<iter_difference_t<I>> size() const requires (K == subrange_kind::sized);
Effects:
  • If StoreSize is true, equivalent to: return size_­;
  • Otherwise, equivalent to: return to-unsigned-like(end_­ - begin_­);
[[nodiscard]] constexpr subrange next(iter_difference_t<I> n = 1) const & requires forward_iterator<I>;
Effects: Equivalent to:
auto tmp = *this;
tmp.advance(n);
return tmp;
[[nodiscard]] constexpr subrange next(iter_difference_t<I> n = 1) &&;
Effects: Equivalent to:
advance(n);
return std::move(*this);
[[nodiscard]] constexpr subrange prev(iter_difference_t<I> n = 1) const requires bidirectional_­iterator<I>;
Effects: Equivalent to:
auto tmp = *this;
tmp.advance(-n);
return tmp;
constexpr subrange& advance(iter_difference_t<I> n);
Effects: Equivalent to:
  • If StoreSize is true,
    auto d = n - ranges::advance(begin_, n, end_);
    if (d >= 0)
      size_ -= to-unsigned-like(d);
    else
      size_ += to-unsigned-like(-d);
    return *this;
    
  • Otherwise,
    ranges::advance(begin_, n, end_);
    return *this;
    
template<size_t N, class I, class S, subrange_kind K> requires (N < 2) constexpr auto get(const subrange<I, S, K>& r); template<size_t N, class I, class S, subrange_kind K> requires (N < 2) constexpr auto get(subrange<I, S, K>&& r);
Effects: Equivalent to:
if constexpr (N == 0)
  return r.begin();
else
  return r.end();

24.5.4 Dangling iterator handling [range.dangling]

The tag type dangling is used together with the template aliases borrowed_­iterator_­t and borrowed_­subrange_­t to indicate that an algorithm that typically returns an iterator into or subrange of a range argument does not return an iterator or subrange which could potentially reference a range whose lifetime has ended for a particular rvalue range argument which does not model borrowed_­range ([range.range]).
namespace std::ranges {
  struct dangling {
    constexpr dangling() noexcept = default;
    template<class... Args>
      constexpr dangling(Args&&...) noexcept { }
  };
}
Example
:
vector<int> f();
auto result1 = ranges::find(f(), 42);                                   // #1
static_assert(same_as<decltype(result1), ranges::dangling>);
auto vec = f();
auto result2 = ranges::find(vec, 42);                                   // #2
static_assert(same_as<decltype(result2), vector<int>::iterator>);
auto result3 = ranges::find(subrange{vec}, 42);                         // #3
static_assert(same_as<decltype(result3), vector<int>::iterator>);
The call to ranges​::​find at #1 returns ranges​::​dangling since f() is an rvalue vector; the vector could potentially be destroyed before a returned iterator is dereferenced.
However, the calls at #2 and #3 both return iterators since the lvalue vec and specializations of subrange model borrowed_­range.
— end example
 ]

24.6 Range factories [range.factories]

This subclause defines range factories, which are utilities to create a view.
Range factories are declared in namespace std​::​ranges​::​views.

24.6.1 Empty view [range.empty]

24.6.1.1 Overview [range.empty.overview]

empty_­view produces a view of no elements of a particular type.
Example
:
empty_view<int> e;
static_assert(ranges::empty(e));
static_assert(0 == e.size());
— end example
 ]

24.6.1.2 Class template empty_­view [range.empty.view]

namespace std::ranges {
  template<class T>
    requires is_object_v<T>
  class empty_view : public view_interface<empty_view<T>> {
  public:
    static constexpr T* begin() noexcept { return nullptr; }
    static constexpr T* end() noexcept { return nullptr; }
    static constexpr T* data() noexcept { return nullptr; }
    static constexpr size_t size() noexcept { return 0; }
    static constexpr bool empty() noexcept { return true; }
  };
}

24.6.2 Single view [range.single]

24.6.2.1 Overview [range.single.overview]

single_­view produces a view that contains exactly one element of a specified value.
The name views​::​single denotes a customization point object ([customization.point.object]).
Given a subexpression E, the expression views​::​single(E) is expression-equivalent to single_­view{E}.
Example
:
single_view s{4};
for (int i : s)
  cout << i;        // prints 4
— end example
 ]

24.6.2.2 Class template single_­view [range.single.view]

namespace std::ranges {
  template<copy_constructible T>
    requires is_object_v<T>
  class single_view : public view_interface<single_view<T>> {
  private:
    semiregular-box<T> value_;      // exposition only (see [range.semi.wrap])
  public:
    single_view() = default;
    constexpr explicit single_view(const T& t);
    constexpr explicit single_view(T&& t);
    template<class... Args>
      requires constructible_from<T, Args...>
    constexpr single_view(in_place_t, Args&&... args);

    constexpr T* begin() noexcept;
    constexpr const T* begin() const noexcept;
    constexpr T* end() noexcept;
    constexpr const T* end() const noexcept;
    static constexpr size_t size() noexcept;
    constexpr T* data() noexcept;
    constexpr const T* data() const noexcept;
  };
}
constexpr explicit single_view(const T& t);
Effects: Initializes value_­ with t.
constexpr explicit single_view(T&& t);
Effects: Initializes value_­ with std​::​move(t).
template<class... Args> constexpr single_view(in_place_t, Args&&... args);
Effects: Initializes value_­ as if by value_­{in_­place, std​::​forward<Args>(args)...}.
constexpr T* begin() noexcept; constexpr const T* begin() const noexcept;
Effects: Equivalent to: return data();
constexpr T* end() noexcept; constexpr const T* end() const noexcept;
Effects: Equivalent to: return data() + 1;
static constexpr size_t size() noexcept;
Effects: Equivalent to: return 1;
constexpr T* data() noexcept; constexpr const T* data() const noexcept;
Effects: Equivalent to: return value_­.operator->();

24.6.3 Iota view [range.iota]

24.6.3.1 Overview [range.iota.overview]

iota_­view generates a sequence of elements by repeatedly incrementing an initial value.
The name views​::​iota denotes a customization point object ([customization.point.object]).
Given subexpressions E and F, the expressions views​::​iota(E) and views​::​iota(E, F) are expression-equivalent to iota_­view{E} and iota_­view{E, F}, respectively.
Example
:
for (int i : iota_view{1, 10})
  cout << i << ' '; // prints: 1 2 3 4 5 6 7 8 9
— end example
 ]

24.6.3.2 Class template iota_­view [range.iota.view]

namespace std::ranges {
  template<class I>
    concept decrementable =     // exposition only
      see below;
  template<class I>
    concept advanceable =       // exposition only
      see below;

  template<weakly_incrementable W, semiregular Bound = unreachable_sentinel_t>
    requires weakly-equality-comparable-with<W, Bound> && semiregular<W>
  class iota_view : public view_interface<iota_view<W, Bound>> {
  private:
    // [range.iota.iterator], class iota_­view​::​iterator
    struct iterator;            // exposition only
    // [range.iota.sentinel], class iota_­view​::​sentinel
    struct sentinel;            // exposition only
    W value_ = W();             // exposition only
    Bound bound_ = Bound();     // exposition only
  public:
    iota_view() = default;
    constexpr explicit iota_view(W value);
    constexpr iota_view(type_identity_t<W> value,
                        type_identity_t<Bound> bound);
    constexpr iota_view(iterator first, sentinel last) : iota_view(*first, last.bound_) {}

    constexpr iterator begin() const;
    constexpr auto end() const;
    constexpr iterator end() const requires same_as<W, Bound>;

    constexpr auto size() const requires see below;
  };

  template<class W, class Bound>
    requires (!is-integer-like<W> || !is-integer-like<Bound> ||
              (is-signed-integer-like<W> == is-signed-integer-like<Bound>))
    iota_view(W, Bound) -> iota_view<W, Bound>;
}
Let IOTA-DIFF-T(W) be defined as follows:
  • If W is not an integral type, or if it is an integral type and sizeof(iter_­difference_­t<W>) is greater than sizeof(W), then IOTA-DIFF-T(W) denotes iter_­difference_­t<W>.
  • Otherwise, IOTA-DIFF-T(W) is a signed integer type of width greater than the width of W if such a type exists.
  • Otherwise, IOTA-DIFF-T(W) is an unspecified signed-integer-like type ([iterator.concept.winc]) of width not less than the width of W.
    Note
    : It is unspecified whether this type satisfies weakly_­incrementable. — end note
     ]
The exposition-only decrementable concept is equivalent to:
template<class I> concept decrementable = incrementable<I> && requires(I i) { { --i } -> same_­as<I&>; { i-- } -> same_­as<I>; };
When an object is in the domain of both pre- and post-decrement, the object is said to be decrementable.
Let a and b be equal objects of type I.
I models decrementable only if
  • If a and b are decrementable, then the following are all true:
  • If a and b are incrementable, then bool(--(++a) == b).
The exposition-only advanceable concept is equivalent to:
template<class I> concept advanceable = decrementable<I> && totally_­ordered<I> && requires(I i, const I j, const IOTA-DIFF-T(I) n) { { i += n } -> same_­as<I&>; { i -= n } -> same_­as<I&>; I(j + n); I(n + j); I(j - n); { j - j } -> convertible_­to<IOTA-DIFF-T(I)>; };
Let D be IOTA-DIFF-T(I).
Let a and b be objects of type I such that b is reachable from a after n applications of ++a, for some value n of type D.
I models advanceable only if
  • (a += n) is equal to b.
  • addressof(a += n) is equal to addressof(a).
  • I(a + n) is equal to (a += n).
  • For any two positive values x and y of type D, if I(a + D(x + y)) is well-defined, then I(a + D(x + y)) is equal to I(I(a + x) + y).
  • I(a + D(0)) is equal to a.
  • If I(a + D(n - 1)) is well-defined, then I(a + n) is equal to [](I c) { return ++c; }(I(a + D(n - 1))).
  • (b += -n) is equal to a.
  • (b -= n) is equal to a.
  • addressof(b -= n) is equal to addressof(b).
  • I(b - n) is equal to (b -= n).
  • D(b - a) is equal to n.
  • D(a - b) is equal to D(-n).
  • bool(a <= b) is true.
constexpr explicit iota_view(W value);
Preconditions: Bound denotes unreachable_­sentinel_­t or Bound() is reachable from value.
Effects: Initializes value_­ with value.
constexpr iota_view(type_identity_t<W> value, type_identity_t<Bound> bound);
Preconditions: Bound denotes unreachable_­sentinel_­t or bound is reachable from value.
When W and Bound model totally_­ordered_­with, then bool(value <= bound) is true.
Effects: Initializes value_­ with value and bound_­ with bound.
constexpr iterator begin() const;
Effects: Equivalent to: return iterator{value_­};
constexpr auto end() const;
Effects: Equivalent to:
if constexpr (same_as<Bound, unreachable_sentinel_t>)
  return unreachable_sentinel;
else
  return sentinel{bound_};
constexpr iterator end() const requires same_­as<W, Bound>;
Effects: Equivalent to: return iterator{bound_­};
constexpr auto size() const requires see below;
Effects: Equivalent to:
if constexpr (is-integer-like<W> && is-integer-like<Bound>)
  return (value_ < 0)
    ? ((bound_ < 0)
      ? to-unsigned-like(-value_) - to-unsigned-like(-bound_)
      : to-unsigned-like(bound_) + to-unsigned-like(-value_))
    : to-unsigned-like(bound_) - to-unsigned-like(value_);
else
  return to-unsigned-like(bound_ - value_);
Remarks: The expression in the requires-clause is equivalent to
(same_as<W, Bound> && advanceable<W>) || (integral<W> && integral<Bound>) ||
  sized_sentinel_for<Bound, W>

24.6.3.3 Class iota_­view​::​iterator [range.iota.iterator]

namespace std::ranges {
  template<weakly_incrementable W, semiregular Bound>
    requires weakly-equality-comparable-with<W, Bound>
  struct iota_view<W, Bound>::iterator {
  private:
    W value_ = W();             // exposition only
  public:
    using iterator_concept = see below;
    using iterator_category = input_iterator_tag;
    using value_type = W;
    using difference_type = IOTA-DIFF-T(W);

    iterator() = default;
    constexpr explicit iterator(W value);

    constexpr W operator*() const noexcept(is_nothrow_copy_constructible_v<W>);

    constexpr iterator& operator++();
    constexpr void operator++(int);
    constexpr iterator operator++(int) requires incrementable<W>;

    constexpr iterator& operator--() requires decrementable<W>;
    constexpr iterator operator--(int) requires decrementable<W>;

    constexpr iterator& operator+=(difference_type n)
      requires advanceable<W>;
    constexpr iterator& operator-=(difference_type n)
      requires advanceable<W>;
    constexpr W operator[](difference_type n) const
      requires advanceable<W>;

    friend constexpr bool operator==(const iterator& x, const iterator& y)
      requires equality_comparable<W>;

    friend constexpr bool operator<(const iterator& x, const iterator& y)
      requires totally_ordered<W>;
    friend constexpr bool operator>(const iterator& x, const iterator& y)
      requires totally_ordered<W>;
    friend constexpr bool operator<=(const iterator& x, const iterator& y)
      requires totally_ordered<W>;
    friend constexpr bool operator>=(const iterator& x, const iterator& y)
      requires totally_ordered<W>;
    friend constexpr auto operator<=>(const iterator& x, const iterator& y)
      requires totally_ordered<W> && three_way_comparable<W>;

    friend constexpr iterator operator+(iterator i, difference_type n)
      requires advanceable<W>;
    friend constexpr iterator operator+(difference_type n, iterator i)
      requires advanceable<W>;

    friend constexpr iterator operator-(iterator i, difference_type n)
      requires advanceable<W>;
    friend constexpr difference_type operator-(const iterator& x, const iterator& y)
      requires advanceable<W>;
  };
}
iterator​::​iterator_­concept is defined as follows:
  • If W models advanceable, then iterator_­concept is random_­access_­iterator_­tag.
  • Otherwise, if W models decrementable, then iterator_­concept is bidirectional_­iterator_­tag.
  • Otherwise, if W models incrementable, then iterator_­concept is forward_­iterator_­tag.
  • Otherwise, iterator_­concept is input_­iterator_­tag.
Note
:
Overloads for iter_­move and iter_­swap are omitted intentionally.
— end note
 ]
constexpr explicit iterator(W value);
Effects: Initializes value_­ with value.
constexpr W operator*() const noexcept(is_nothrow_copy_constructible_v<W>);
Effects: Equivalent to: return value_­;
Note
:
The noexcept clause is needed by the default iter_­move implementation.
— end note
 ]
constexpr iterator& operator++();
Effects: Equivalent to:
++value_;
return *this;
constexpr void operator++(int);
Effects: Equivalent to ++*this.
constexpr iterator operator++(int) requires incrementable<W>;
Effects: Equivalent to:
auto tmp = *this;
++*this;
return tmp;
constexpr iterator& operator--() requires decrementable<W>;
Effects: Equivalent to:
--value_;
return *this;
constexpr iterator operator--(int) requires decrementable<W>;
Effects: Equivalent to:
auto tmp = *this;
--*this;
return tmp;
constexpr iterator& operator+=(difference_type n) requires advanceable<W>;
Effects: Equivalent to:
if constexpr (is-integer-like<W> && !is-signed-integer-like<W>) {
  if (n >= difference_type(0))
    value_ += static_cast<W>(n);
  else
    value_ -= static_cast<W>(-n);
} else {
  value_ += n;
}
return *this;
constexpr iterator& operator-=(difference_type n) requires advanceable<W>;
Effects: Equivalent to:
if constexpr (is-integer-like<W> && !is-signed-integer-like<W>) {
  if (n >= difference_type(0))
    value_ -= static_cast<W>(n);
  else
    value_ += static_cast<W>(-n);
} else {
  value_ -= n;
}
return *this;
constexpr W operator[](difference_type n) const requires advanceable<W>;
Effects: Equivalent to: return W(value_­ + n);
friend constexpr bool operator==(const iterator& x, const iterator& y) requires equality_comparable<W>;
Effects: Equivalent to: return x.value_­ == y.value_­;
friend constexpr bool operator<(const iterator& x, const iterator& y) requires totally_­ordered<W>;
Effects: Equivalent to: return x.value_­ < y.value_­;
friend constexpr bool operator>(const iterator& x, const iterator& y) requires totally_­ordered<W>;
Effects: Equivalent to: return y < x;
friend constexpr bool operator<=(const iterator& x, const iterator& y) requires totally_­ordered<W>;
Effects: Equivalent to: return !(y < x);
friend constexpr bool operator>=(const iterator& x, const iterator& y) requires totally_­ordered<W>;
Effects: Equivalent to: return !(x < y);
friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires totally_­ordered<W> && three_­way_­comparable<W>;
Effects: Equivalent to: return x.value_­ <=> y.value_­;
friend constexpr iterator operator+(iterator i, difference_type n) requires advanceable<W>;
Effects: Equivalent to: return i += n;
friend constexpr iterator operator+(difference_type n, iterator i) requires advanceable<W>;
Effects: Equivalent to: return i + n;
friend constexpr iterator operator-(iterator i, difference_type n) requires advanceable<W>;
Effects: Equivalent to: return i -= n;
friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires advanceable<W>;
Effects: Equivalent to:
using D = difference_type;
if constexpr (is-integer-like<W>) {
  if constexpr (is-signed-integer-like<W>)
    return D(D(x.value_) - D(y.value_));
  else
    return (y.value_ > x.value_)
      ? D(-D(y.value_ - x.value_))
      : D(x.value_ - y.value_);
} else {
  return x.value_ - y.value_;
}

24.6.3.4 Class iota_­view​::​sentinel [range.iota.sentinel]

namespace std::ranges {
  template<weakly_incrementable W, semiregular Bound>
    requires weakly-equality-comparable-with<W, Bound>
  struct iota_view<W, Bound>::sentinel {
  private:
    Bound bound_ = Bound();     // exposition only
  public:
    sentinel() = default;
    constexpr explicit sentinel(Bound bound);

    friend constexpr bool operator==(const iterator& x, const sentinel& y);

    friend constexpr iter_difference_t<W> operator-(const iterator& x, const sentinel& y)
      requires sized_sentinel_for<Bound, W>;
    friend constexpr iter_difference_t<W> operator-(const sentinel& x, const iterator& y)
      requires sized_sentinel_for<Bound, W>;
  };
}
constexpr explicit sentinel(Bound bound);
Effects: Initializes bound_­ with bound.
friend constexpr bool operator==(const iterator& x, const sentinel& y);
Effects: Equivalent to: return x.value_­ == y.bound_­;
friend constexpr iter_difference_t<W> operator-(const iterator& x, const sentinel& y) requires sized_­sentinel_­for<Bound, W>;
Effects: Equivalent to: return x.value_­ - y.bound_­;
friend constexpr iter_difference_t<W> operator-(const sentinel& x, const iterator& y) requires sized_­sentinel_­for<Bound, W>;
Effects: Equivalent to: return -(y - x);

24.6.4 Istream view [range.istream]

24.6.4.1 Overview [range.istream.overview]

basic_­istream_­view models input_­range and reads (using operator>>) successive elements from its corresponding input stream.
Example
:
auto ints = istringstream{"0 1  2   3     4"};
ranges::copy(istream_view<int>(ints), ostream_iterator<int>{cout, "-"});
// prints 0-1-2-3-4-
— end example
 ]

24.6.4.2 Class template basic_­istream_­view [range.istream.view]

namespace std::ranges {
  template<class Val, class CharT, class Traits>
    concept stream-extractable =                // exposition only
      requires(basic_istream<CharT, Traits>& is, Val& t) {
         is >> t;
      };

  template<movable Val, class CharT, class Traits>
    requires default_initializable<Val> &&
             stream-extractable<Val, CharT, Traits>
  class basic_istream_view : public view_interface<basic_istream_view<Val, CharT, Traits>> {
  public:
    basic_istream_view() = default;
    constexpr explicit basic_istream_view(basic_istream<CharT, Traits>& stream);

    constexpr auto begin()
    {
      if (stream_) {
        *stream_ >> object_;
      }
      return iterator{*this};
    }

    constexpr default_sentinel_t end() const noexcept;

  private:
    struct iterator;                                    // exposition only
    basic_istream<CharT, Traits>* stream_ = nullptr;    // exposition only
    Val object_ = Val();                                // exposition only
  };
}
constexpr explicit basic_istream_view(basic_istream<CharT, Traits>& stream);
Effects: Initializes stream_­ with addressof(stream).
constexpr default_sentinel_t end() const noexcept;
Effects: Equivalent to: return default_­sentinel;
template<class Val, class CharT, class Traits> basic_istream_view<Val, CharT, Traits> istream_view(basic_istream<CharT, Traits>& s);
Effects: Equivalent to: return basic_­istream_­view<Val, CharT, Traits>{s};

24.6.4.3 Class template basic_­istream_­view​::​iterator [range.istream.iterator]

namespace std::ranges {
  template<movable Val, class CharT, class Traits>
    requires default_initializable<Val> &&
             stream-extractable<Val, CharT, Traits>
  class basic_istream_view<Val, CharT, Traits>::iterator {      // exposition only
  public:
    using iterator_concept = input_iterator_tag;
    using difference_type = ptrdiff_t;
    using value_type = Val;

    iterator() = default;
    constexpr explicit iterator(basic_istream_view& parent) noexcept;

    iterator(const iterator&) = delete;
    iterator(iterator&&) = default;

    iterator& operator=(const iterator&) = delete;
    iterator& operator=(iterator&&) = default;

    iterator& operator++();
    void operator++(int);

    Val& operator*() const;

    friend bool operator==(const iterator& x, default_sentinel_t);

  private:
    basic_istream_view* parent_ = nullptr;                      // exposition only
  };
}
constexpr explicit iterator(basic_istream_view& parent) noexcept;
Effects: Initializes parent_­ with addressof(parent).
iterator& operator++();
Preconditions: parent_­->stream_­ != nullptr is true.
Effects: Equivalent to:
*parent_->stream_>> parent_->object_;
return *this;
void operator++(int);
Preconditions: parent_­->stream_­ != nullptr is true.
Effects: Equivalent to ++*this.
Val& operator*() const;
Preconditions: parent_­->stream_­ != nullptr is true.
Effects: Equivalent to: return parent_­->object_­;
friend bool operator==(const iterator& x, default_sentinel_t);
Effects: Equivalent to: return x.parent_­ == nullptr || !*x.parent_­->stream_­;

24.7 Range adaptors [range.adaptors]

This subclause defines range adaptors, which are utilities that transform a range into a view with custom behaviors.
These adaptors can be chained to create pipelines of range transformations that evaluate lazily as the resulting view is iterated.
Range adaptors are declared in namespace std​::​ranges​::​views.
The bitwise OR operator is overloaded for the purpose of creating adaptor chain pipelines.
The adaptors also support function call syntax with equivalent semantics.
Example
:
vector<int> ints{0,1,2,3,4,5};
auto even = [](int i){ return 0 == i % 2; };
auto square = [](int i) { return i * i; };
for (int i : ints | views::filter(even) | views::transform(square)) {
  cout << i << ' '; // prints: 0 4 16
}
assert(ranges::equal(ints | views::filter(even), views::filter(ints, even)));
— end example
 ]

24.7.1 Range adaptor objects [range.adaptor.object]

A range adaptor closure object is a unary function object that accepts a viewable_­range argument and returns a view.
For a range adaptor closure object C and an expression R such that decltype((R)) models viewable_­range, the following expressions are equivalent and yield a view:
C(R)
R | C
Given an additional range adaptor closure object D, the expression C | D is well-formed and produces another range adaptor closure object such that the following two expressions are equivalent:
R | C | D
R | (C | D)
A range adaptor object is a customization point object ([customization.point.object]) that accepts a viewable_­range as its first argument and returns a view.
If a range adaptor object accepts only one argument, then it is a range adaptor closure object.
If a range adaptor object accepts more than one argument, then the following expressions are equivalent:
adaptor(range, args...)
adaptor(args...)(range)
range | adaptor(args...)
In this case, adaptor(args...) is a range adaptor closure object.

24.7.2 Semiregular wrapper [range.semi.wrap]

Many types in this subclause are specified in terms of an exposition-only class template semiregular-box.
semiregular-box<T> behaves exactly like optional<T> with the following differences:
  • semiregular-box<T> constrains its type parameter T with copy_­constructible<T> && is_­object_­v<T>.
  • If T models default_­initializable, the default constructor of semiregular-box<T> is equivalent to:
    constexpr semiregular-box() noexcept(is_nothrow_default_constructible_v<T>)
      : semiregular-box{in_place}
    { }
    
  • If assignable_­from<T&, const T&> is not modeled, the copy assignment operator is equivalent to:
    semiregular-box& operator=(const semiregular-box& that)
      noexcept(is_nothrow_copy_constructible_v<T>)
    {
      if (that) emplace(*that);
      else reset();
      return *this;
    }
    
  • If assignable_­from<T&, T> is not modeled, the move assignment operator is equivalent to:
    semiregular-box& operator=(semiregular-box&& that)
      noexcept(is_nothrow_move_constructible_v<T>)
    {
      if (that) emplace(std::move(*that));
      else reset();
      return *this;
    }
    

24.7.3 All view [range.all]

views​::​all returns a view that includes all elements of its range argument.
The name views​::​all denotes a range adaptor object ([range.adaptor.object]).
Given a subexpression E, the expression views​::​all(E) is expression-equivalent to:
  • decay-copy(E) if the decayed type of E models view.
  • Otherwise, ref_­view{E} if that expression is well-formed.
  • Otherwise, subrange{E}.

24.7.3.1 Class template ref_­view [range.ref.view]

ref_­view is a view of the elements of some other range.
namespace std::ranges {
  template<range R>
    requires is_object_v<R>
  class ref_view : public view_interface<ref_view<R>> {
  private:
    R* r_ = nullptr;            // exposition only
  public:
    constexpr ref_view() noexcept = default;

    template<not-same-as<ref_view> T>
      requires see below
    constexpr ref_view(T&& t);

    constexpr R& base() const { return *r_; }

    constexpr iterator_t<R> begin() const { return ranges::begin(*r_); }
    constexpr sentinel_t<R> end() const { return ranges::end(*r_); }

    constexpr bool empty() const
      requires requires { ranges::empty(*r_); }
    { return ranges::empty(*r_); }

    constexpr auto size() const requires sized_range<R>
    { return ranges::size(*r_); }

    constexpr auto data() const requires contiguous_range<R>
    { return ranges::data(*r_); }
  };
  template<class R>
    ref_view(R&) -> ref_view<R>;
}
template<not-same-as<ref_view> T> requires see below constexpr ref_view(T&& t);
Remarks: Let FUN denote the exposition-only functions
void FUN(R&);
void FUN(R&&) = delete;
The expression in the requires-clause is equivalent to
convertible_to<T, R&> && requires { FUN(declval<T>()); }
Effects: Initializes r_­ with addressof(static_­cast<R&>(std​::​forward<T>(t))).

24.7.4 Filter view [range.filter]

24.7.4.1 Overview [range.filter.overview]

filter_­view presents a view of the elements of an underlying sequence that satisfy a predicate.
The name views​::​filter denotes a range adaptor object ([range.adaptor.object]).
Given subexpressions E and P, the expression views​::​filter(E, P) is expression-equivalent to filter_­view{E, P}.
Example
:
vector<int> is{ 0, 1, 2, 3, 4, 5, 6 };
filter_view evens{is, [](int i) { return 0 == i % 2; }};
for (int i : evens)
  cout << i << ' '; // prints: 0 2 4 6
— end example
 ]

24.7.4.2 Class template filter_­view [range.filter.view]

namespace std::ranges {
  template<input_range V, indirect_unary_predicate<iterator_t<V>> Pred>
    requires view<V> && is_object_v<Pred>
  class filter_view : public view_interface<filter_view<V, Pred>> {
  private:
    V base_ = V();                      // exposition only
    semiregular-box<Pred> pred_;  // exposition only

    // [range.filter.iterator], class filter_­view​::​iterator
    class iterator;                     // exposition only
    // [range.filter.sentinel], class filter_­view​::​sentinel
    class sentinel;                     // exposition only

  public:
    filter_view() = default;
    constexpr filter_view(V base, Pred pred);

    constexpr V base() const& requires copy_constructible<V> { return base_; }
    constexpr V base() && { return std::move(base_); }

    constexpr const Pred& pred() const;

    constexpr iterator begin();
    constexpr auto end() {
      if constexpr (common_range<V>)
        return iterator{*this, ranges::end(base_)};
      else
        return sentinel{*this};
    }
  };

  template<class R, class Pred>
    filter_view(R&&, Pred) -> filter_view<views::all_t<R>, Pred>;
}
constexpr filter_view(V base, Pred pred);
Effects: Initializes base_­ with std​::​move(base) and initializes pred_­ with std​::​move(pred).
constexpr const Pred& pred() const;
Effects: Equivalent to: return *pred_­;
constexpr iterator begin();
Preconditions: pred_­.has_­value().
Returns: {*this, ranges​::​find_­if(base_­, ref(*pred_­))}.
Remarks: In order to provide the amortized constant time complexity required by the range concept when filter_­view models forward_­range, this function caches the result within the filter_­view for use on subsequent calls.

24.7.4.3 Class filter_­view​::​iterator [range.filter.iterator]

namespace std::ranges {
  template<input_range V, indirect_unary_predicate<iterator_t<V>> Pred>
    requires view<V> && is_object_v<Pred>
  class filter_view<V, Pred>::iterator {
  private:
    iterator_t<V> current_ = iterator_t<V>();   // exposition only
    filter_view* parent_ = nullptr;             // exposition only
  public:
    using iterator_concept  = see below;
    using iterator_category = see below;
    using value_type        = range_value_t<V>;
    using difference_type   = range_difference_t<V>;

    iterator() = default;
    constexpr iterator(filter_view& parent, iterator_t<V> current);

    constexpr iterator_t<V> base() const &
      requires copyable<iterator_t<V>>;
    constexpr iterator_t<V> base() &&;
    constexpr range_reference_t<V> operator*() const;
    constexpr iterator_t<V> operator->() const
      requires has-arrow<iterator_t<V>> && copyable<iterator_t<V>>;

    constexpr iterator& operator++();
    constexpr void operator++(int);
    constexpr iterator operator++(int) requires forward_range<V>;

    constexpr iterator& operator--() requires bidirectional_range<V>;
    constexpr iterator operator--(int) requires bidirectional_range<V>;

    friend constexpr bool operator==(const iterator& x, const iterator& y)
      requires equality_comparable<iterator_t<V>>;

    friend constexpr range_rvalue_reference_t<V> iter_move(const iterator& i)
      noexcept(noexcept(ranges::iter_move(i.current_)));
    friend constexpr void iter_swap(const iterator& x, const iterator& y)
      noexcept(noexcept(ranges::iter_swap(x.current_, y.current_)))
      requires indirectly_swappable<iterator_t<V>>;
  };
}
Modification of the element a filter_­view​::​iterator denotes is permitted, but results in undefined behavior if the resulting value does not satisfy the filter predicate.
iterator​::​iterator_­concept is defined as follows:
  • If V models bidirectional_­range, then iterator_­concept denotes bidirectional_­iterator_­tag.
  • Otherwise, if V models forward_­range, then iterator_­concept denotes forward_­iterator_­tag.
  • Otherwise, iterator_­concept denotes input_­iterator_­tag.
iterator​::​iterator_­category is defined as follows:
  • Let C denote the type iterator_­traits<iterator_­t<V>>​::​iterator_­category.
  • If C models derived_­from<bidirectional_­iterator_­tag>, then iterator_­category denotes bidirectional_­iterator_­tag.
  • Otherwise, if C models derived_­from<forward_­iterator_­tag>, then iterator_­category denotes forward_­iterator_­tag.
  • Otherwise, iterator_­category denotes C.
constexpr iterator(filter_view& parent, iterator_t<V> current);
Effects: Initializes current_­ with std​::​move(current) and parent_­ with addressof(parent).
constexpr iterator_t<V> base() const & requires copyable<iterator_t<V>>;
Effects: Equivalent to: return current_­;
constexpr iterator_t<V> base() &&;
Effects: Equivalent to: return std​::​move(current_­);
constexpr range_reference_t<V> operator*() const;
Effects: Equivalent to: return *current_­;
constexpr iterator_t<V> operator->() const requires has-arrow<iterator_t<V>> && copyable<iterator_t<V>>;
Effects: Equivalent to: return current_­;
constexpr iterator& operator++();
Effects: Equivalent to:
current_ = ranges::find_if(std::move(++current_), ranges::end(parent_->base_),
                           ref(*parent_->pred_));
return *this;
constexpr void operator++(int);
Effects: Equivalent to ++*this.
constexpr iterator operator++(int) requires forward_­range<V>;
Effects: Equivalent to:
auto tmp = *this;
++*this;
return tmp;
constexpr iterator& operator--() requires bidirectional_­range<V>;
Effects: Equivalent to:
do
  --current_;
while (!invoke(*parent_->pred_, *current_));
return *this;
constexpr iterator operator--(int) requires bidirectional_­range<V>;
Effects: Equivalent to:
auto tmp = *this;
--*this;
return tmp;
friend constexpr bool operator==(const iterator& x, const iterator& y) requires equality_comparable<iterator_t<V>>;
Effects: Equivalent to: return x.current_­ == y.current_­;
friend constexpr range_rvalue_reference_t<V> iter_move(const iterator& i) noexcept(noexcept(ranges::iter_move(i.current_­)));
Effects: Equivalent to: return ranges​::​iter_­move(i.current_­);
friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(noexcept(ranges::iter_swap(x.current_­, y.current_­))) requires indirectly_­swappable<iterator_t<V>>;
Effects: Equivalent to ranges​::​iter_­swap(x.current_­, y.current_­).

24.7.4.4 Class filter_­view​::​sentinel [range.filter.sentinel]

namespace std::ranges {
  template<input_range V, indirect_unary_predicate<iterator_t<V>> Pred>
    requires view<V> && is_object_v<Pred>
  class filter_view<V, Pred>::sentinel {
  private:
    sentinel_t<V> end_ = sentinel_t<V>();       // exposition only
  public:
    sentinel() = default;
    constexpr explicit sentinel(filter_view& parent);

    constexpr sentinel_t<V> base() const;

    friend constexpr bool operator==(const iterator& x, const sentinel& y);
  };
}
constexpr explicit sentinel(filter_view& parent);
Effects: Initializes end_­ with ranges​::​end(parent.base_­).
constexpr sentinel_t<V> base() const;
Effects: Equivalent to: return end_­;
friend constexpr bool operator==(const iterator& x, const sentinel& y);
Effects: Equivalent to: return x.current_­ == y.end_­;

24.7.5 Transform view [range.transform]

24.7.5.1 Overview [range.transform.overview]

transform_­view presents a view of an underlying sequence after applying a transformation function to each element.
The name views​::​transform denotes a range adaptor object ([range.adaptor.object]).
Given subexpressions E and F, the expression views​::​transform(E, F) is expression-equivalent to transform_­view{E, F}.
Example
:
vector<int> is{ 0, 1, 2, 3, 4 };
transform_view squares{is, [](int i) { return i * i; }};
for (int i : squares)
  cout << i << ' '; // prints: 0 1 4 9 16
— end example
 ]

24.7.5.2 Class template transform_­view [range.transform.view]

namespace std::ranges {
  template<input_range V, copy_constructible F>
    requires view<V> && is_object_v<F> &&
             regular_invocable<F&, range_reference_t<V>> &&
             can-reference<invoke_result_t<F&, range_reference_t<V>>>
  class transform_view : public view_interface<transform_view<V, F>> {
  private:
    // [range.transform.iterator], class template transform_­view​::​iterator
    template<bool> struct iterator;             // exposition only
    // [range.transform.sentinel], class template transform_­view​::​sentinel
    template<bool> struct sentinel;             // exposition only

    V base_ = V();                              // exposition only
    semiregular-box<F> fun_;                    // exposition only

  public:
    transform_view() = default;
    constexpr transform_view(V base, F fun);

    constexpr V base() const& requires copy_constructible<V> { return base_; }
    constexpr V base() && { return std::move(base_); }

    constexpr iterator<false> begin();
    constexpr iterator<true> begin() const
      requires range<const V> &&
               regular_invocable<const F&, range_reference_t<const V>>;

    constexpr sentinel<false> end();
    constexpr iterator<false> end() requires common_range<V>;
    constexpr sentinel<true> end() const
      requires range<const V> &&
               regular_invocable<const F&, range_reference_t<const V>>;
    constexpr iterator<true> end() const
      requires common_range<const V> &&
               regular_invocable<const F&, range_reference_t<const V>>;

    constexpr auto size() requires sized_range<V> { return ranges::size(base_); }
    constexpr auto size() const requires sized_range<const V>
    { return ranges::size(base_); }
  };

  template<class R, class F>
    transform_view(R&&, F) -> transform_view<views::all_t<R>, F>;
}
constexpr transform_view(V base, F fun);
Effects: Initializes base_­ with std​::​move(base) and fun_­ with std​::​move(fun).
constexpr iterator<false> begin();
Effects: Equivalent to:
return iterator<false>{*this, ranges::begin(base_)};
constexpr iterator<true> begin() const requires range<const V> && regular_invocable<const F&, range_reference_t<const V>>;
Effects: Equivalent to:
return iterator<true>{*this, ranges::begin(base_)};
constexpr sentinel<false> end();
Effects: Equivalent to:
return sentinel<false>{ranges::end(base_)};
constexpr iterator<false> end() requires common_range<V>;
Effects: Equivalent to:
return iterator<false>{*this, ranges::end(base_)};
constexpr sentinel<true> end() const requires range<const V> && regular_invocable<const F&, range_reference_t<const V>>;
Effects: Equivalent to:
return sentinel<true>{ranges::end(base_)};
constexpr iterator<true> end() const requires common_range<const V> && regular_invocable<const F&, range_reference_t<const V>>;
Effects: Equivalent to:
return iterator<true>{*this, ranges::end(base_)};

24.7.5.3 Class template transform_­view​::​iterator [range.transform.iterator]

namespace std::ranges {
  template<input_range V, copy_constructible F>
    requires view<V> && is_object_v<F> &&
             regular_invocable<F&, range_reference_t<V>> &&
             can-reference<invoke_result_t<F&, range_reference_t<V>>>
  template<bool Const>
  class transform_view<V, F>::iterator {
  private:
    using Parent =                              // exposition only
      conditional_t<Const, const transform_view, transform_view>;
    using Base   =                              // exposition only
      conditional_t<Const, const V, V>;
    iterator_t<Base> current_ =                 // exposition only
      iterator_t<Base>();
    Parent* parent_ = nullptr;                  // exposition only
  public:
    using iterator_concept  = see below;
    using iterator_category = see below;
    using value_type        =
      remove_cvref_t<invoke_result_t<F&, range_reference_t<Base>>>;
    using difference_type   = range_difference_t<Base>;

    iterator() = default;
    constexpr iterator(Parent& parent, iterator_t<Base> current);
    constexpr iterator(iterator<!Const> i)
      requires Const && convertible_to<iterator_t<V>, iterator_t<Base>>;

    constexpr iterator_t<Base> base() const &
      requires copyable<iterator_t<Base>>;
    constexpr iterator_t<Base> base() &&;
    constexpr decltype(auto) operator*() const
    { return invoke(*parent_->fun_, *current_); }

    constexpr iterator& operator++();
    constexpr void operator++(int);
    constexpr iterator operator++(int) requires forward_range<Base>;

    constexpr iterator& operator--() requires bidirectional_range<Base>;
    constexpr iterator operator--(int) requires bidirectional_range<Base>;

    constexpr iterator& operator+=(difference_type n)
      requires random_access_range<Base>;
    constexpr iterator& operator-=(difference_type n)
      requires random_access_range<Base>;
    constexpr decltype(auto) operator[](difference_type n) const
      requires random_access_range<Base>
    { return invoke(*parent_->fun_, current_[n]); }

    friend constexpr bool operator==(const iterator& x, const iterator& y)
      requires equality_comparable<iterator_t<Base>>;

    friend constexpr bool operator<(const iterator& x, const iterator& y)
      requires random_access_range<Base>;
    friend constexpr bool operator>(const iterator& x, const iterator& y)
      requires random_access_range<Base>;
    friend constexpr bool operator<=(const iterator& x, const iterator& y)
      requires random_access_range<Base>;
    friend constexpr bool operator>=(const iterator& x, const iterator& y)
      requires random_access_range<Base>;
    friend constexpr auto operator<=>(const iterator& x, const iterator& y)
      requires random_access_range<Base> && three_way_comparable<iterator_t<Base>>;

    friend constexpr iterator operator+(iterator i, difference_type n)
      requires random_access_range<Base>;
    friend constexpr iterator operator+(difference_type n, iterator i)
      requires random_access_range<Base>;

    friend constexpr iterator operator-(iterator i, difference_type n)
      requires random_access_range<Base>;
    friend constexpr difference_type operator-(const iterator& x, const iterator& y)
      requires random_access_range<Base>;

    friend constexpr decltype(auto) iter_move(const iterator& i)
      noexcept(noexcept(invoke(*i.parent_->fun_, *i.current_)))
    {
      if constexpr (is_lvalue_reference_v<decltype(*i)>)
        return std::move(*i);
      else
        return *i;
    }

    friend constexpr void iter_swap(const iterator& x, const iterator& y)
      noexcept(noexcept(ranges::iter_swap(x.current_, y.current_)))
      requires indirectly_swappable<iterator_t<Base>>;
  };
}
iterator​::​iterator_­concept is defined as follows:
  • If V models random_­access_­range, then iterator_­concept denotes random_­access_­iterator_­tag.
  • Otherwise, if V models bidirectional_­range, then iterator_­concept denotes bidirectional_­iterator_­tag.
  • Otherwise, if V models forward_­range, then iterator_­concept denotes forward_­iterator_­tag.
  • Otherwise, iterator_­concept denotes input_­iterator_­tag.
iterator​::​iterator_­category is defined as follows: Let C denote the type iterator_­traits<iterator_­t<Base>>​::​iterator_­category.
  • If is_­lvalue_­reference_­v<invoke_­result_­t<F&, range_­reference_­t<Base>>> is true, then
    • if C models derived_­from<contiguous_­iterator_­tag>, iterator_­category denotes random_­access_­iterator_­tag;
    • otherwise, iterator_­category denotes C.
  • Otherwise, iterator_­category denotes input_­iterator_­tag.
constexpr iterator(Parent& parent, iterator_t<Base> current);
Effects: Initializes current_­ with std​::​move(current) and parent_­ with addressof(parent).
constexpr iterator(iterator<!Const> i) requires Const && convertible_­to<iterator_t<V>, iterator_t<Base>>;
Effects: Initializes current_­ with std​::​move(i.current_­) and parent_­ with i.parent_­.
constexpr iterator_t<Base> base() const & requires copyable<iterator_t<Base>>;
Effects: Equivalent to: return current_­;
constexpr iterator_t<Base> base() &&;
Effects: Equivalent to: return std​::​move(current_­);
constexpr iterator& operator++();
Effects: Equivalent to:
++current_;
return *this;
constexpr void operator++(int);
Effects: Equivalent to ++current_­.
constexpr iterator operator++(int) requires forward_­range<Base>;
Effects: Equivalent to:
auto tmp = *this;
++*this;
return tmp;
constexpr iterator& operator--() requires bidirectional_­range<Base>;
Effects: Equivalent to:
--current_;
return *this;
constexpr iterator operator--(int) requires bidirectional_­range<Base>;
Effects: Equivalent to:
auto tmp = *this;
--*this;
return tmp;
constexpr iterator& operator+=(difference_type n) requires random_­access_­range<Base>;
Effects: Equivalent to:
current_ += n;
return *this;
constexpr iterator& operator-=(difference_type n) requires random_­access_­range<Base>;
Effects: Equivalent to:
current_ -= n;
return *this;
friend constexpr bool operator==(const iterator& x, const iterator& y) requires equality_comparable<iterator_t<Base>>;
Effects: Equivalent to: return x.current_­ == y.current_­;
friend constexpr bool operator<(const iterator& x, const iterator& y) requires random_­access_­range<Base>;
Effects: Equivalent to: return x.current_­ < y.current_­;
friend constexpr bool operator>(const iterator& x, const iterator& y) requires random_­access_­range<Base>;
Effects: Equivalent to: return y < x;
friend constexpr bool operator<=(const iterator& x, const iterator& y) requires random_­access_­range<Base>;
Effects: Equivalent to: return !(y < x);
friend constexpr bool operator>=(const iterator& x, const iterator& y) requires random_­access_­range<Base>;
Effects: Equivalent to: return !(x < y);
friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires random_­access_­range<Base> && three_­way_­comparable<iterator_t<Base>>;
Effects: Equivalent to: return x.current_­ <=> y.current_­;
friend constexpr iterator operator+(iterator i, difference_type n) requires random_­access_­range<Base>; friend constexpr iterator operator+(difference_type n, iterator i) requires random_­access_­range<Base>;
Effects: Equivalent to: return iterator{*i.parent_­, i.current_­ + n};
friend constexpr iterator operator-(iterator i, difference_type n) requires random_­access_­range<Base>;
Effects: Equivalent to: return iterator{*i.parent_­, i.current_­ - n};
friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires random_­access_­range<Base>;
Effects: Equivalent to: return x.current_­ - y.current_­;
friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(noexcept(ranges::iter_swap(x.current_­, y.current_­))) requires indirectly_­swappable<iterator_t<Base>>;
Effects: Equivalent to ranges​::​iter_­swap(x.current_­, y.current_­).

24.7.5.4 Class template transform_­view​::​sentinel [range.transform.sentinel]

namespace std::ranges {
  template<input_range V, copy_constructible F>
    requires view<V> && is_object_v<F> &&
             regular_invocable<F&, range_reference_t<V>> &&
             can-reference<invoke_result_t<F&, range_reference_t<V>>>
  template<bool Const>
  class transform_view<V, F>::sentinel {
  private:
    using Parent =                                      // exposition only
      conditional_t<Const, const transform_view, transform_view>;
    using Base = conditional_t<Const, const V, V>;      // exposition only
    sentinel_t<Base> end_ = sentinel_t<Base>();         // exposition only
  public:
    sentinel() = default;
    constexpr explicit sentinel(sentinel_t<Base> end);
    constexpr sentinel(sentinel<!Const> i)
      requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;

    constexpr sentinel_t<Base> base() const;

    friend constexpr bool operator==(const iterator<Const>& x, const sentinel& y);

    friend constexpr range_difference_t<Base>
      operator-(const iterator<Const>& x, const sentinel& y)
        requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
    friend constexpr range_difference_t<Base>
      operator-(const sentinel& y, const iterator<Const>& x)
        requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
  };
}
constexpr explicit sentinel(sentinel_t<Base> end);
Effects: Initializes end_­ with end.
constexpr sentinel(sentinel<!Const> i) requires Const && convertible_­to<sentinel_t<V>, sentinel_t<Base>>;
Effects: Initializes end_­ with std​::​move(i.end_­).
constexpr sentinel_t<Base> base() const;
Effects: Equivalent to: return end_­;
friend constexpr bool operator==(const iterator<Const>& x, const sentinel& y);
Effects: Equivalent to: return x.current_­ == y.end_­;
friend constexpr range_difference_t<Base> operator-(const iterator<Const>& x, const sentinel& y) requires sized_­sentinel_­for<sentinel_t<Base>, iterator_t<Base>>;
Effects: Equivalent to: return x.current_­ - y.end_­;
friend constexpr range_difference_t<Base> operator-(const sentinel& y, const iterator<Const>& x) requires sized_­sentinel_­for<sentinel_t<Base>, iterator_t<Base>>;
Effects: Equivalent to: return y.end_­ - x.current_­;

24.7.6 Take view [range.take]

24.7.6.1 Overview [range.take.overview]

take_­view produces a view of the first N elements from another view, or all the elements if the adapted view contains fewer than N.
The name views​::​take denotes a range adaptor object ([range.adaptor.object]).
Let E and F be expressions, let T be remove_­cvref_­t<decltype((E))>, and let D be range_­difference_­t<decltype((E))>.
If decltype((F)) does not model convertible_­to<D>, views​::​take(E, F) is ill-formed.
Otherwise, the expression views​::​take(E, F) is expression-equivalent to:
  • If T is a specialization of ranges​::​empty_­view ([range.empty.view]), then ((void) F, decay-copy(E)).
  • Otherwise, if T models random_­access_­range and sized_­range and is then T{ranges​::​begin(E), ranges​::​begin(E) + min<D>(ranges​::​size(E), F)}, except that E is evaluated only once.
  • Otherwise, ranges​::​take_­view{E, F}.
Example
:
vector<int> is{0,1,2,3,4,5,6,7,8,9};
take_view few{is, 5};
for (int i : few)
  cout << i << ' '; // prints: 0 1 2 3 4
— end example
 ]

24.7.6.2 Class template take_­view [range.take.view]

namespace std::ranges {
  template<view V>
  class take_view : public view_interface<take_view<V>> {
  private:
    V base_ = V();                                      // exposition only
    range_difference_t<V> count_ = 0;                   // exposition only
    // [range.take.sentinel], class template take_­view​::​sentinel
    template<bool> struct sentinel;                     // exposition only
  public:
    take_view() = default;
    constexpr take_view(V base, range_difference_t<V> count);

    constexpr V base() const& requires copy_constructible<V> { return base_; }
    constexpr V base() && { return std::move(base_); }

    constexpr auto begin() requires (!simple-view<V>) {
      if constexpr (sized_range<V>) {
        if constexpr (random_access_range<V>)
          return ranges::begin(base_);
        else {
          auto sz = size();
          return counted_iterator{ranges::begin(base_), sz};
        }
      } else
        return counted_iterator{ranges::begin(base_), count_};
    }

    constexpr auto begin() const requires range<const V> {
      if constexpr (sized_range<const V>) {
        if constexpr (random_access_range<const V>)
          return ranges::begin(base_);
        else {
          auto sz = size();
          return counted_iterator{ranges::begin(base_), sz};
        }
      } else
        return counted_iterator{ranges::begin(base_), count_};
    }

    constexpr auto end() requires (!simple-view<V>) {
      if constexpr (sized_range<V>) {
        if constexpr (random_access_range<V>)
          return ranges::begin(base_) + size();
        else
          return default_sentinel;
      } else
        return sentinel<false>{ranges::end(base_)};
    }

    constexpr auto end() const requires range<const V> {
      if constexpr (sized_range<const V>) {
        if constexpr (random_access_range<const V>)
          return ranges::begin(base_) + size();
        else
          return default_sentinel;
      } else
        return sentinel<true>{ranges::end(base_)};
    }

    constexpr auto size() requires sized_range<V> {
      auto n = ranges::size(base_);
      return ranges::min(n, static_cast<decltype(n)>(count_));
    }

    constexpr auto size() const requires sized_range<const V> {
      auto n = ranges::size(base_);
      return ranges::min(n, static_cast<decltype(n)>(count_));
    }
  };

  template<range R>
    take_view(R&&, range_difference_t<R>)
      -> take_view<views::all_t<R>>;
}
constexpr take_view(V base, range_difference_t<V> count);
Effects: Initializes base_­ with std​::​move(base) and count_­ with count.

24.7.6.3 Class template take_­view​::​sentinel [range.take.sentinel]

namespace std::ranges {
  template<view V>
  template<bool Const>
  class take_view<V>::sentinel {
  private:
    using Base = conditional_t<Const, const V, V>;      // exposition only
    using CI = counted_iterator<iterator_t<Base>>;      // exposition only
    sentinel_t<Base> end_ = sentinel_t<Base>();         // exposition only
  public:
    sentinel() = default;
    constexpr explicit sentinel(sentinel_t<Base> end);
    constexpr sentinel(sentinel<!Const> s)
      requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;

    constexpr sentinel_t<Base> base() const;

    friend constexpr bool operator==(const CI& y, const sentinel& x);
  };
}
constexpr explicit sentinel(sentinel_t<Base> end);
Effects: Initializes end_­ with end.
constexpr sentinel(sentinel<!Const> s) requires Const && convertible_­to<sentinel_t<V>, sentinel_t<Base>>;
Effects: Initializes end_­ with std​::​move(s.end_­).
constexpr sentinel_t<Base> base() const;
Effects: Equivalent to: return end_­;
friend constexpr bool operator==(const CI& y, const sentinel& x);
Effects: Equivalent to: return y.count() == 0 || y.base() == x.end_­;

24.7.7 Take while view [range.take.while]

24.7.7.1 Overview [range.take.while.overview]

Given a unary predicate pred and a view r, take_­while_­view produces a view of the range [begin(r), ranges​::​find_­if_­not(r, pred)).
The name views​::​take_­while denotes a range adaptor object ([range.adaptor.object]).
Given subexpressions E and F, the expression views​::​take_­while(E, F) is expression-equivalent to take_­while_­view{E, F}.
Example
:
auto input = istringstream{"0 1 2 3 4 5 6 7 8 9"};
auto small = [](const auto x) noexcept { return x < 5; };
auto small_ints = istream_view<int>(input) | views::take_while(small);
for (const auto i : small_ints) {
  cout << i << ' ';                             // prints 0 1 2 3 4
}
auto i = 0;
input >> i;
cout << i;                                      // prints 6
— end example
 ]

24.7.7.2 Class template take_­while_­view [range.take.while.view]

namespace std::ranges {
  template<view V, class Pred>
    requires input_range<V> && is_object_v<Pred> &&
             indirect_unary_predicate<const Pred, iterator_t<V>>
  class take_while_view : public view_interface<take_while_view<V, Pred>> {
    // [range.take.while.sentinel], class template take_­while_­view​::​sentinel
    template<bool> class sentinel;                      // exposition only

    V base_ = V();                                      // exposition only
    semiregular-box<Pred> pred_;                        // exposition only

  public:
    take_while_view() = default;
    constexpr take_while_view(V base, Pred pred);

    constexpr V base() const& requires copy_constructible<V> { return base_; }
    constexpr V base() && { return std::move(base_); }

    constexpr const Pred& pred() const;

    constexpr auto begin() requires (!simple-view<V>)
    { return ranges::begin(base_); }

    constexpr auto begin() const requires range<const V>
    { return ranges::begin(base_); }

    constexpr auto end() requires (!simple-view<V>)
    { return sentinel<false>(ranges::end(base_), addressof(*pred_)); }

    constexpr auto end() const requires range<const V>
    { return sentinel<true>(ranges::end(base_), addressof(*pred_)); }
  };

  template<class R, class Pred>
    take_while_view(R&&, Pred) -> take_while_view<views::all_t<R>, Pred>;
}
constexpr take_while_view(V base, Pred pred);
Effects: Initializes base_­ with std​::​move(base) and pred_­ with std​::​move(pred).
constexpr const Pred& pred() const;
Effects: Equivalent to: return *pred_­;

24.7.7.3 Class template take_­while_­view​::​sentinel [range.take.while.sentinel]

namespace std::ranges {
  template<view V, class Pred>
    requires input_range<V> && is_object_v<Pred> &&
             indirect_unary_predicate<const Pred, iterator_t<V>>
  template<bool Const>
  class take_while_view<V, Pred>::sentinel {            // exposition only
    using Base = conditional_t<Const, const V, V>;      // exposition only

    sentinel_t<Base> end_ = sentinel_t<Base>();         // exposition only
    const Pred* pred_ = nullptr;                        // exposition only
  public:
    sentinel() = default;
    constexpr explicit sentinel(sentinel_t<Base> end, const Pred* pred);
    constexpr sentinel(sentinel<!Const> s)
      requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;

    constexpr sentinel_t<Base> base() const { return end_; }

    friend constexpr bool operator==(const iterator_t<Base>& x, const sentinel& y);
  };
}
constexpr explicit sentinel(sentinel_t<Base> end, const Pred* pred);
Effects: Initializes end_­ with end and pred_­ with pred.
constexpr sentinel(sentinel<!Const> s) requires Const && convertible_­to<sentinel_t<V>, sentinel_t<Base>>;
Effects: Initializes end_­ with s.end_­ and pred_­ with s.pred_­.
friend constexpr bool operator==(const iterator_t<Base>& x, const sentinel& y);
Effects: Equivalent to: return y.end_­ == x || !invoke(*y.pred_­, *x);

24.7.8 Drop view [range.drop]

24.7.8.1 Overview [range.drop.overview]

drop_­view produces a view excluding the first N elements from another view, or an empty range if the adapted view contains fewer than N elements.
The name views​::​drop denotes a range adaptor object ([range.adaptor.object]).
Let E and F be expressions, let T be remove_­cvref_­t<decltype((E))>, and let D be range_­difference_­t<decltype((E))>.
If decltype((F)) does not model convertible_­to<D>, views​::​drop(E, F) is ill-formed.
Otherwise, the expression views​::​drop(E, F) is expression-equivalent to:
  • If T is a specialization of ranges​::​empty_­view ([range.empty.view]), then ((void) F, decay-copy(E)).
  • Otherwise, if T models random_­access_­range and sized_­range and is then T{ranges​::​begin(E) + min<D>(ranges​::​size(E), F), ranges​::​end(E)}, except that E is evaluated only once.
  • Otherwise, ranges​::​drop_­view{E, F}.
Example
:
auto ints = views::iota(0) | views::take(10);
auto latter_half = drop_view{ints, 5};
for (auto i : latter_half) {
  cout << i << ' ';                             // prints 5 6 7 8 9
}
— end example
 ]

24.7.8.2 Class template drop_­view [range.drop.view]

namespace std::ranges {
  template<view V>
  class drop_view : public view_interface<drop_view<V>> {
  public:
    drop_view() = default;
    constexpr drop_view(V base, range_difference_t<V> count);

    constexpr V base() const& requires copy_constructible<V> { return base_; }
    constexpr V base() && { return std::move(base_); }

    constexpr auto begin()
      requires (!(simple-view<V> && random_access_range<V>));
    constexpr auto begin() const
      requires random_access_range<const V>;

    constexpr auto end()
      requires (!simple-view<V>)
    { return ranges::end(base_); }

    constexpr auto end() const
      requires range<const V>
    { return ranges::end(base_); }

    constexpr auto size()
      requires sized_range<V>
    {
      const auto s = ranges::size(base_);
      const auto c = static_cast<decltype(s)>(count_);
      return s < c ? 0 : s - c;
    }

    constexpr auto size() const
      requires sized_range<const V>
    {
      const auto s = ranges::size(base_);
      const auto c = static_cast<decltype(s)>(count_);
      return s < c ? 0 : s - c;
    }
  private:
    V base_ = V();                              // exposition only
    range_difference_t<V> count_ = 0;           // exposition only
  };

  template<class R>
    drop_view(R&&, range_difference_t<R>) -> drop_view<views::all_t<R>>;
}
constexpr drop_view(V base, range_difference_t<V> count);
Preconditions: count >= 0 is true.
Effects: Initializes base_­ with std​::​move(base) and count_­ with count.
constexpr auto begin() requires (!(simple-view<V> && random_­access_­range<V>)); constexpr auto begin() const requires random_access_range<const V>;
Returns: ranges​::​next(ranges​::​begin(base_­), count_­, ranges​::​end(base_­)).
Remarks: In order to provide the amortized constant-time complexity required by the range concept when drop_­view models forward_­range, the first overload caches the result within the drop_­view for use on subsequent calls.
Note
:
Without this, applying a reverse_­view over a drop_­view would have quadratic iteration complexity.
— end note
 ]

24.7.9 Drop while view [range.drop.while]

24.7.9.1 Overview [range.drop.while.overview]

Given a unary predicate pred and a view r, drop_­while_­view produces a view of the range [ranges​::​find_­if_­not(r, pred), ranges​::​end(r)).
The name views​::​drop_­while denotes a range adaptor object ([range.adaptor.object]).
Given subexpressions E and F, the expression views​::​drop_­while(E, F) is expression-equivalent to drop_­while_­view{E, F}.
Example
:
constexpr auto source = "  \t   \t   \t   hello there";
auto is_invisible = [](const auto x) { return x == ' ' || x == '\t'; };
auto skip_ws = drop_while_view{source, is_invisible};
for (auto c : skip_ws) {
  cout << c;                                    // prints hello there with no leading space
}
— end example
 ]

24.7.9.2 Class template drop_­while_­view [range.drop.while.view]

namespace std::ranges {
  template<view V, class Pred>
    requires input_range<V> && is_object_v<Pred> &&
             indirect_unary_predicate<const Pred, iterator_t<V>>
  class drop_while_view : public view_interface<drop_while_view<V, Pred>> {
  public:
    drop_while_view() = default;
    constexpr drop_while_view(V base, Pred pred);

    constexpr V base() const& requires copy_constructible<V> { return base_; }
    constexpr V base() && { return std::move(base_); }

    constexpr const Pred& pred() const;

    constexpr auto begin();

    constexpr auto end()
    { return ranges::end(base_); }

  private:
    V base_ = V();                                      // exposition only
    semiregular-box<Pred> pred_;                        // exposition only
  };

  template<class R, class Pred>
    drop_while_view(R&&, Pred) -> drop_while_view<views::all_t<R>, Pred>;
}
constexpr drop_while_view(V base, Pred pred);
Effects: Initializes base_­ with std​::​move(base) and pred_­ with std​::​move(pred).
constexpr const Pred& pred() const;
Effects: Equivalent to: return *pred_­;
constexpr auto begin();
Returns: ranges​::​find_­if_­not(base_­, cref(*pred_­)).
Remarks: In order to provide the amortized constant-time complexity required by the range concept when drop_­while_­view models forward_­range, the first call caches the result within the drop_­while_­view for use on subsequent calls.
Note
:
Without this, applying a reverse_­view over a drop_­while_­view would have quadratic iteration complexity.
— end note
 ]

24.7.10 Join view [range.join]

24.7.10.1 Overview [range.join.overview]

join_­view flattens a view of ranges into a view.
The name views​::​join denotes a range adaptor object ([range.adaptor.object]).
Given a subexpression E, the expression views​::​join(E) is expression-equivalent to join_­view{E}.
Example
:
vector<string> ss{"hello", " ", "world", "!"};
join_view greeting{ss};
for (char ch : greeting)
  cout << ch;                                   // prints: hello world!
— end example
 ]

24.7.10.2 Class template join_­view [range.join.view]

namespace std::ranges {
  template<input_range V>
    requires view<V> && input_range<range_reference_t<V>> &&
             (is_reference_v<range_reference_t<V>> ||
              view<range_value_t<V>>)
  class join_view : public view_interface<join_view<V>> {
  private:
    using InnerRng =                    // exposition only
      range_reference_t<V>;
    // [range.join.iterator], class template join_­view​::​iterator
    template<bool Const>
      struct iterator;                  // exposition only
    // [range.join.sentinel], class template join_­view​::​sentinel
    template<bool Const>
      struct sentinel;                  // exposition only

    V base_ = V();                      // exposition only
    views::all_t<InnerRng> inner_ =     // exposition only, present only when !is_­reference_­v<InnerRng>
      views::all_t<InnerRng>();
  public:
    join_view() = default;
    constexpr explicit join_view(V base);

    constexpr V base() const& requires copy_constructible<V> { return base_; }
    constexpr V base() && { return std::move(base_); }

    constexpr auto begin() {
      constexpr bool use_const = simple-view<V> &&
                                 is_reference_v<range_reference_t<V>>;
      return iterator<use_const>{*this, ranges::begin(base_)};
    }

    constexpr auto begin() const
    requires input_range<const V> &&
             is_reference_v<range_reference_t<const V>> {
      return iterator<true>{*this, ranges::begin(base_)};
    }

    constexpr auto end() {
      if constexpr (forward_range<V> &&
                    is_reference_v<InnerRng> && forward_range<InnerRng> &&
                    common_range<V> && common_range<InnerRng>)
        return iterator<simple-view<V>>{*this, ranges::end(base_)};
      else
        return sentinel<simple-view<V>>{*this};
    }

    constexpr auto end() const
    requires input_range<const V> &&
             is_reference_v<range_reference_t<const V>> {
      if constexpr (forward_range<const V> &&
                    is_reference_v<range_reference_t<const V>> &&
                    forward_range<range_reference_t<const V>> &&
                    common_range<const V> &&
                    common_range<range_reference_t<const V>>)
        return iterator<true>{*this, ranges::end(base_)};
      else
        return sentinel<true>{*this};
    }
  };

  template<class R>
    explicit join_view(R&&) -> join_view<views::all_t<R>>;
}
constexpr explicit join_view(V base);
Effects: Initializes base_­ with std​::​move(base).

24.7.10.3 Class template join_­view​::​iterator [range.join.iterator]

namespace std::ranges {
  template<input_range V>
    requires view<V> && input_range<range_reference_t<V>> &&
             (is_reference_v<range_reference_t<V>> ||
              view<range_value_t<V>>)
  template<bool Const>
  struct join_view<V>::iterator {
  private:
    using Parent =                                              // exposition only
      conditional_t<Const, const join_view, join_view>;
    using Base   = conditional_t<Const, const V, V>;            // exposition only

    static constexpr bool ref-is-glvalue =                      // exposition only
      is_reference_v<range_reference_t<Base>>;

    iterator_t<Base> outer_ = iterator_t<Base>();               // exposition only
    iterator_t<range_reference_t<Base>> inner_ =                // exposition only
      iterator_t<range_reference_t<Base>>();
    Parent* parent_ = nullptr;                                  // exposition only

    constexpr void satisfy();                                   // exposition only
  public:
    using iterator_concept  = see below;
    using iterator_category = see below;
    using value_type        = range_value_t<range_reference_t<Base>>;
    using difference_type   = see below;

    iterator() = default;
    constexpr iterator(Parent& parent, iterator_t<Base> outer);
    constexpr iterator(iterator<!Const> i)
      requires Const &&
               convertible_to<iterator_t<V>, iterator_t<Base>> &&
               convertible_to<iterator_t<InnerRng>,
                              iterator_t<range_reference_t<Base>>>;

    constexpr decltype(auto) operator*() const { return *inner_; }

    constexpr iterator_t<Base> operator->() const
      requires has-arrow<iterator_t<Base>> && copyable<iterator_t<Base>>;

    constexpr iterator& operator++();
    constexpr void operator++(int);
    constexpr iterator operator++(int)
      requires ref-is-glvalue && forward_range<Base> &&
               forward_range<range_reference_t<Base>>;

    constexpr iterator& operator--()
      requires ref-is-glvalue && bidirectional_range<Base> &&
               bidirectional_range<range_reference_t<Base>> &&
               common_range<range_reference_t<Base>>;

    constexpr iterator operator--(int)
      requires ref-is-glvalue && bidirectional_range<Base> &&
               bidirectional_range<range_reference_t<Base>> &&
               common_range<range_reference_t<Base>>;

    friend constexpr bool operator==(const iterator& x, const iterator& y)
      requires ref-is-glvalue && equality_comparable<iterator_t<Base>> &&
               equality_comparable<iterator_t<range_reference_t<Base>>>;

    friend constexpr decltype(auto) iter_move(const iterator& i)
    noexcept(noexcept(ranges::iter_move(i.inner_))) {
      return ranges::iter_move(i.inner_);
    }

    friend constexpr void iter_swap(const iterator& x, const iterator& y)
      noexcept(noexcept(ranges::iter_swap(x.inner_, y.inner_)));
  };
}
iterator​::​iterator_­concept is defined as follows:
  • If ref-is-glvalue is true and Base and range_­reference_­t<Base> each model bidirectional_­range, then iterator_­concept denotes bidirectional_­iterator_­tag.
  • Otherwise, if ref-is-glvalue is true and Base and range_­reference_­t<Base> each model forward_­range, then iterator_­concept denotes forward_­iterator_­tag.
  • Otherwise, iterator_­concept denotes input_­iterator_­tag.
iterator​::​iterator_­category is defined as follows:
  • Let OUTERC denote iterator_­traits<iterator_­t<Base>>​::​iterator_­category, and let INNERC denote iterator_­traits<iterator_­t<range_­reference_­t<Base>>>​::​iterator_­category.
  • If ref-is-glvalue is true and OUTERC and INNERC each model derived_­from<bidirectional_­iterator_­tag>, iterator_­category denotes bidirectional_­iterator_­tag.
  • Otherwise, if ref-is-glvalue is true and OUTERC and INNERC each model derived_­from<forward_­iterator_­tag>, iterator_­category denotes forward_­iterator_­tag.
  • Otherwise, if OUTERC and INNERC each model derived_­from<input_­iterator_­tag>, iterator_­category denotes input_­iterator_­tag.
  • Otherwise, iterator_­category denotes output_­iterator_­tag.
iterator​::​difference_­type denotes the type:
common_type_t<
  range_difference_t<Base>,
  range_difference_t<range_reference_t<Base>>>
join_­view iterators use the satisfy function to skip over empty inner ranges.
constexpr void satisfy(); // exposition only
Effects: Equivalent to:
auto update_inner = [this](range_reference_t<Base> x) -> auto& {
  if constexpr (ref-is-glvalue) // x is a reference
    return x;
  else
    return (parent_->inner_ = views::all(std::move(x)));
};

for (; outer_ != ranges::end(parent_->base_); ++outer_) {
  auto& inner = update_inner(*outer_);
  inner_ = ranges::begin(inner);
  if (inner_ != ranges::end(inner))
    return;
}
if constexpr (ref-is-glvalue)
  inner_ = iterator_t<range_reference_t<Base>>();
constexpr iterator(Parent& parent, iterator_t<Base> outer);
Effects: Initializes outer_­ with std​::​move(outer) and parent_­ with addressof(parent); then calls satisfy().
constexpr iterator(iterator<!Const> i) requires Const && convertible_­to<iterator_t<V>, iterator_t<Base>> && convertible_­to<iterator_t<InnerRng>, iterator_t<range_reference_t<Base>>>;
Effects: Initializes outer_­ with std​::​move(i.outer_­), inner_­ with std​::​move(i.inner_­), and parent_­ with i.parent_­.
constexpr iterator_t<Base> operator->() const requires has-arrow<iterator_t<Base>> && copyable<iterator_t<Base>>;
Effects: Equivalent to return inner_­;
constexpr iterator& operator++();
Let inner-range be:
  • If ref-is-glvalue is true, *outer_­.
  • Otherwise, parent_­->inner_­.
Effects: Equivalent to:
auto&& inner_rng = inner-range;
if (++inner_ == ranges::end(inner_rng)) {
  ++outer_;
  satisfy();
}
return *this;
constexpr void operator++(int);
Effects: Equivalent to: ++*this.
constexpr iterator operator++(int) requires ref-is-glvalue && forward_­range<Base> && forward_­range<range_reference_t<Base>>;
Effects: Equivalent to:
auto tmp = *this;
++*this;
return tmp;
constexpr iterator& operator--() requires ref-is-glvalue && bidirectional_­range<Base> && bidirectional_­range<range_reference_t<Base>> && common_range<range_reference_t<Base>>;
Effects: Equivalent to:
if (outer_ == ranges::end(parent_->base_))
  inner_ = ranges::end(*--outer_);
while (inner_ == ranges::begin(*outer_))
  inner_ = ranges::end(*--outer_);
--inner_;
return *this;
constexpr iterator operator--(int) requires ref-is-glvalue && bidirectional_­range<Base> && bidirectional_­range<range_reference_t<Base>> && common_range<range_reference_t<Base>>;
Effects: Equivalent to:
auto tmp = *this;
--*this;
return tmp;
friend constexpr bool operator==(const iterator& x, const iterator& y) requires ref-is-glvalue && equality_comparable<iterator_t<Base>> && equality_comparable<iterator_t<range_reference_t<Base>>>;
Effects: Equivalent to: return x.outer_­ == y.outer_­ && x.inner_­ == y.inner_­;
friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(noexcept(ranges::iter_swap(x.inner_­, y.inner_­)));
Effects: Equivalent to: return ranges​::​iter_­swap(x.inner_­, y.inner_­);

24.7.10.4 Class template join_­view​::​sentinel [range.join.sentinel]

namespace std::ranges {
  template<input_range V>
    requires view<V> && input_range<range_reference_t<V>> &&
             (is_reference_v<range_reference_t<V>> ||
              view<range_value_t<V>>)
  template<bool Const>
  struct join_view<V>::sentinel {
  private:
    using Parent =                                      // exposition only
      conditional_t<Const, const join_view, join_view>;
    using Base   = conditional_t<Const, const V, V>;    // exposition only
    sentinel_t<Base> end_ = sentinel_t<Base>();         // exposition only
  public:
    sentinel() = default;

    constexpr explicit sentinel(Parent& parent);
    constexpr sentinel(sentinel<!Const> s)
      requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;

    friend constexpr bool operator==(const iterator<Const>& x, const sentinel& y);
  };
}
constexpr explicit sentinel(Parent& parent);
Effects: Initializes end_­ with ranges​::​end(parent.base_­).
constexpr sentinel(sentinel<!Const> s) requires Const && convertible_­to<sentinel_t<V>, sentinel_t<Base>>;
Effects: Initializes end_­ with std​::​move(s.end_­).
friend constexpr bool operator==(const iterator<Const>& x, const sentinel& y);
Effects: Equivalent to: return x.outer_­ == y.end_­;

24.7.11 Split view [range.split]

24.7.11.1 Overview [range.split.overview]

split_­view takes a view and a delimiter, and splits the view into subranges on the delimiter.
The delimiter can be a single element or a view of elements.
The name views​::​split denotes a range adaptor object ([range.adaptor.object]).
Given subexpressions E and F, the expression views​::​split(E, F) is expression-equivalent to split_­view{E, F}.
Example
:
string str{"the quick brown fox"};
split_view sentence{str, ' '};
for (auto word : sentence) {
  for (char ch : word)
    cout << ch;
  cout << '*';
}
// The above prints: the*quick*brown*fox*
— end example
 ]

24.7.11.2 Class template split_­view [range.split.view]

namespace std::ranges {
  template<auto> struct require-constant;       // exposition only

  template<class R>
  concept tiny-range =                          // exposition only
    sized_range<R> &&
    requires { typename require-constant<remove_reference_t<R>::size()>; } &&
    (remove_reference_t<R>::size() <= 1);

  template<input_range V, forward_range Pattern>
    requires view<V> && view<Pattern> &&
             indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
             (forward_range<V> || tiny-range<Pattern>)
  class split_view : public view_interface<split_view<V, Pattern>> {
  private:
    V base_ = V();                              // exposition only
    Pattern pattern_ = Pattern();               // exposition only
    iterator_t<V> current_ = iterator_t<V>();   // exposition only, present only if !forward_­range<V>
    // [range.split.outer], class template split_­view​::​outer-iterator
    template<bool> struct outer-iterator;       // exposition only
    // [range.split.inner], class template split_­view​::​inner-iterator
    template<bool> struct inner-iterator;       // exposition only
  public:
    split_view() = default;
    constexpr split_view(V base, Pattern pattern);

    template<input_range R>
      requires constructible_from<V, views::all_t<R>> &&
               constructible_from<Pattern, single_view<range_value_t<R>>>
    constexpr split_view(R&& r, range_value_t<R> e);

    constexpr V base() const& requires copy_constructible<V> { return base_; }
    constexpr V base() && { return std::move(base_); }

    constexpr auto begin() {
      if constexpr (forward_range<V>)
        return outer-iterator<simple-view<V>>{*this, ranges::begin(base_)};
      else {
        current_ = ranges::begin(base_);
        return outer-iterator<false>{*this};
      }
    }

    constexpr auto begin() const requires forward_range<V> && forward_range<const V> {
      return outer-iterator<true>{*this, ranges::begin(base_)};
    }

    constexpr auto end() requires forward_range<V> && common_range<V> {
      return outer-iterator<simple-view<V>>{*this, ranges::end(base_)};
    }

    constexpr auto end() const {
      if constexpr (forward_range<V> && forward_range<const V> && common_range<const V>)
        return outer-iterator<true>{*this, ranges::end(base_)};
      else
        return default_sentinel;
    }
  };

  template<class R, class P>
    split_view(R&&, P&&) -> split_view<views::all_t<R>, views::all_t<P>>;

  template<input_range R>
    split_view(R&&, range_value_t<R>)
      -> split_view<views::all_t<R>, single_view<range_value_t<R>>>;
}
constexpr split_view(V base, Pattern pattern);
Effects: Initializes base_­ with std​::​move(base), and pattern_­ with std​::​move(pattern).
template<input_­range R> requires constructible_­from<V, views::all_t<R>> && constructible_­from<Pattern, single_view<range_value_t<R>>> constexpr split_view(R&& r, range_value_t<R> e);
Effects: Initializes base_­ with views​::​all(std​::​forward<R>(r)), and pattern_­ with single_­view{​std​::​move(e)}.

24.7.11.3 Class template split_­view​::​outer-iterator [range.split.outer]

namespace std::ranges {
  template<input_range V, forward_range Pattern>
    requires view<V> && view<Pattern> &&
             indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
             (forward_range<V> || tiny-range<Pattern>)
  template<bool Const>
  struct split_view<V, Pattern>::outer-iterator {
  private:
    using Parent =                          // exposition only
      conditional_t<Const, const split_view, split_view>;
    using Base   =                          // exposition only
      conditional_t<Const, const V, V>;
    Parent* parent_ = nullptr;              // exposition only
    iterator_t<Base> current_ =             // exposition only, present only if V models forward_­range
      iterator_t<Base>();

  public:
    using iterator_concept  =
      conditional_t<forward_range<Base>, forward_iterator_tag, input_iterator_tag>;
    using iterator_category = input_iterator_tag;
    // [range.split.outer.value], class split_­view​::​outer-iterator​::​value_­type
    struct value_type;
    using difference_type   = range_difference_t<Base>;

    outer-iterator() = default;
    constexpr explicit outer-iterator(Parent& parent)
      requires (!forward_range<Base>);
    constexpr outer-iterator(Parent& parent, iterator_t<Base> current)
      requires forward_range<Base>;
    constexpr outer-iterator(outer-iterator<!Const> i)
      requires Const && convertible_to<iterator_t<V>, iterator_t<Base>>;

    constexpr value_type operator*() const;

    constexpr outer-iterator& operator++();
    constexpr decltype(auto) operator++(int) {
      if constexpr (forward_range<Base>) {
        auto tmp = *this;
        ++*this;
        return tmp;
      } else
        ++*this;
    }

    friend constexpr bool operator==(const outer-iterator& x, const outer-iterator& y)
      requires forward_range<Base>;

    friend constexpr bool operator==(const outer-iterator& x, default_sentinel_t);
  };
}
Many of the following specifications refer to the notional member current of outer-iterator.
current is equivalent to current_­ if V models forward_­range, and parent_­->current_­ otherwise.
constexpr explicit outer-iterator(Parent& parent) requires (!forward_­range<Base>);
Effects: Initializes parent_­ with addressof(parent).
constexpr outer-iterator(Parent& parent, iterator_t<Base> current) requires forward_­range<Base>;
Effects: Initializes parent_­ with addressof(parent) and current_­ with std​::​move(current).
constexpr outer-iterator(outer-iterator<!Const> i) requires Const && convertible_­to<iterator_t<V>, iterator_t<Base>>;
Effects: Initializes parent_­ with i.parent_­ and current_­ with std​::​move(i.current_­).
constexpr value_type operator*() const;
Effects: Equivalent to: return value_­type{*this};
constexpr outer-iterator& operator++();
Effects: Equivalent to:
const auto end = ranges::end(parent_->base_);
if (current == end) return *this;
const auto [pbegin, pend] = subrange{parent_->pattern_};
if (pbegin == pend) ++current;
else {
  do {
    auto [b, p] = ranges::mismatch(std::move(current), end, pbegin, pend);
    current = std::move(b);
    if (p == pend) {
      break;            // The pattern matched; skip it
    }
  } while (++current != end);
}
return *this;
friend constexpr bool operator==(const outer-iterator& x, const outer-iterator& y) requires forward_­range<Base>;
Effects: Equivalent to: return x.current_­ == y.current_­;
friend constexpr bool operator==(const outer-iterator& x, default_sentinel_t);
Effects: Equivalent to: return x.current == ranges​::​end(x.parent_­->base_­);

24.7.11.4 Class split_­view​::​outer-iterator​::​value_­type [range.split.outer.value]

namespace std::ranges {
  template<input_range V, forward_range Pattern>
    requires view<V> && view<Pattern> &&
             indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
             (forward_range<V> || tiny-range<Pattern>)
  template<bool Const>
  struct split_view<V, Pattern>::outer-iterator<Const>::value_type
    : view_interface<value_type> {
  private:
    outer-iterator i_ = outer-iterator();               // exposition only
  public:
    value_type() = default;
    constexpr explicit value_type(outer-iterator i);

    constexpr inner-iterator<Const> begin() const requires copyable<outer-iterator>;
    constexpr inner-iterator<Const> begin() requires (!copyable<outer-iterator>);
    constexpr default_sentinel_t end() const;
  };
}
constexpr explicit value_type(outer-iterator i);
Effects: Initializes i_­ with std​::​move(i).
constexpr inner-iterator<Const> begin() const requires copyable<outer-iterator>;
Effects: Equivalent to: return inner-iterator<Const>{i_­};
constexpr inner-iterator<Const> begin() requires (!copyable<outer-iterator>);
Effects: Equivalent to: return inner-iterator<Const>{std​::​move(i_­)};
constexpr default_sentinel_t end() const;
Effects: Equivalent to: return default_­sentinel;

24.7.11.5 Class template split_­view​::​inner-iterator [range.split.inner]

namespace std::ranges {
  template<input_range V, forward_range Pattern>
    requires view<V> && view<Pattern> &&
             indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
             (forward_range<V> || tiny-range<Pattern>)
  template<bool Const>
  struct split_view<V, Pattern>::inner-iterator {
  private:
    using Base = conditional_t<Const, const V, V>;      // exposition only
    outer-iterator<Const> i_ = outer-iterator<Const>(); // exposition only
    bool incremented_ = false;                          // exposition only
  public:
    using iterator_concept  = typename outer-iterator<Const>::iterator_concept;
    using iterator_category = see below;
    using value_type        = range_value_t<Base>;
    using difference_type   = range_difference_t<Base>;

    inner-iterator() = default;
    constexpr explicit inner-iterator(outer-iterator<Const> i);

    constexpr decltype(auto) operator*() const { return *i_.current; }

    constexpr inner-iterator& operator++();
    constexpr decltype(auto) operator++(int) {
      if constexpr (forward_range<V>) {
        auto tmp = *this;
        ++*this;
        return tmp;
      } else
        ++*this;
    }

    friend constexpr bool operator==(const inner-iterator& x, const inner-iterator& y)
      requires forward_range<Base>;

    friend constexpr bool operator==(const inner-iterator& x, default_sentinel_t);

    friend constexpr decltype(auto) iter_move(const inner-iterator& i)
    noexcept(noexcept(ranges::iter_move(i.i_.current))) {
      return ranges::iter_move(i.i_.current);
    }

    friend constexpr void iter_swap(const inner-iterator& x, const inner-iterator& y)
      noexcept(noexcept(ranges::iter_swap(x.i_.current, y.i_.current)))
      requires indirectly_swappable<iterator_t<Base>>;
  };
}
The typedef-name iterator_­category denotes:
  • forward_­iterator_­tag if iterator_­traits<iterator_­t<Base>>​::​iterator_­category models
    derived_­from<forward_­iterator_­tag>;
  • otherwise, iterator_­traits<iterator_­t<Base>>​::​iterator_­category.
constexpr explicit inner-iterator(outer-iterator<Const> i);
Effects: Initializes i_­ with std​::​move(i).
constexpr inner-iterator& operator++();
Effects: Equivalent to:
incremented_ = true;
if constexpr (!forward_range<Base>) {
  if constexpr (Pattern::size() == 0) {
    return *this;
  }
}
++i_.current;
return *this;
friend constexpr bool operator==(const inner-iterator& x, const inner-iterator& y) requires forward_­range<Base>;
Effects: Equivalent to: return x.i_­.current == y.i_­.current;
friend constexpr bool operator==(const inner-iterator& x, default_sentinel_t);
Effects: Equivalent to:
auto [pcur, pend] = subrange{x.i_.parent_->pattern_};
auto end = ranges::end(x.i_.parent_->base_);
if constexpr (tiny-range<Pattern>) {
  const auto & cur = x.i_.current;
  if (cur == end) return true;
  if (pcur == pend) return x.incremented_;
  return *cur == *pcur;
} else {
  auto cur = x.i_.current;
  if (cur == end) return true;
  if (pcur == pend) return x.incremented_;
  do {
    if (*cur != *pcur) return false;
    if (++pcur == pend) return true;
  } while (++cur != end);
  return false;
}
friend constexpr void iter_swap(const inner-iterator& x, const inner-iterator& y) noexcept(noexcept(ranges::iter_swap(x.i_­.current, y.i_­.current))) requires indirectly_­swappable<iterator_t<Base>>;
Effects: Equivalent to ranges​::​iter_­swap(x.i_­.current, y.i_­.current).

24.7.12 Counted view [range.counted]

A counted view presents a view of the elements of the counted range ([iterator.requirements.general]) for an iterator i and non-negative integer n.
The name views​::​counted denotes a customization point object ([customization.point.object]).
Let E and F be expressions, let T be decay_­t<decltype((E))>, and let D be iter_­difference_­t<T>.
If decltype((F)) does not model convertible_­to<D>, views​::​counted(E, F) is ill-formed.
Note
:
This case can result in substitution failure when views​::​counted(E, F) appears in the immediate context of a template instantiation.
— end note
 ]
Otherwise, views​::​counted(E, F) is expression-equivalent to:
  • If T models contiguous_­iterator, then span{to_­address(E), static_­cast<D>(F)}.
  • Otherwise, if T models random_­access_­iterator, then subrange{E, E + static_­cast<D>(F)}, except that E is evaluated only once.
  • Otherwise, subrange{counted_­iterator{E, F}, default_­sentinel}.

24.7.13 Common view [range.common]

24.7.13.1 Overview [range.common.overview]

common_­view takes a view which has different types for its iterator and sentinel and turns it into a view of the same elements with an iterator and sentinel of the same type.
Note
:
common_­view is useful for calling legacy algorithms that expect a range's iterator and sentinel types to be the same.
— end note
 ]
The name views​::​common denotes a range adaptor object ([range.adaptor.object]).
Given a subexpression E, the expression views​::​common(E) is expression-equivalent to:
  • views​::​all(E), if decltype((E)) models common_­range and views​::​all(E) is a well-formed expression.
  • Otherwise, common_­view{E}.
Example
:
// Legacy algorithm:
template<class ForwardIterator>
size_t count(ForwardIterator first, ForwardIterator last);

template<forward_range R>
void my_algo(R&& r) {
  auto&& common = common_view{r};
  auto cnt = count(common.begin(), common.end());
  // ...
}
— end example
 ]

24.7.13.2 Class template common_­view [range.common.view]

namespace std::ranges {
  template<view V>
    requires (!common_range<V> && copyable<iterator_t<V>>)
  class common_view : public view_interface<common_view<V>> {
  private:
    V base_ = V();  // exposition only
  public:
    common_view() = default;

    constexpr explicit common_view(V r);

    template<viewable_range R>
      requires (!common_range<R> && constructible_from<V, views::all_t<R>>)
    constexpr explicit common_view(R&& r);

    constexpr V base() const& requires copy_constructible<V> { return base_; }
    constexpr V base() && { return std::move(base_); }

    constexpr auto begin() {
      if constexpr (random_access_range<V> && sized_range<V>)
        return ranges::begin(base_);
      else
        return common_iterator<iterator_t<V>, sentinel_t<V>>(ranges::begin(base_));
    }

    constexpr auto begin() const requires range<const V> {
      if constexpr (random_access_range<const V> && sized_range<const V>)
        return ranges::begin(base_);
      else
        return common_iterator<iterator_t<const V>, sentinel_t<const V>>(ranges::begin(base_));
    }

    constexpr auto end() {
      if constexpr (random_access_range<V> && sized_range<V>)
        return ranges::begin(base_) + ranges::size(base_);
      else
        return common_iterator<iterator_t<V>, sentinel_t<V>>(ranges::end(base_));
    }

    constexpr auto end() const requires range<const V> {
      if constexpr (random_access_range<const V> && sized_range<const V>)
        return ranges::begin(base_) + ranges::size(base_);
      else
        return common_iterator<iterator_t<const V>, sentinel_t<const V>>(ranges::end(base_));
    }

    constexpr auto size() requires sized_range<V> {
      return ranges::size(base_);
    }
    constexpr auto size() const requires sized_range<const V> {
      return ranges::size(base_);
    }
  };

  template<class R>
    common_view(R&&) -> common_view<views::all_t<R>>;
}
constexpr explicit common_view(V base);
Effects: Initializes base_­ with std​::​move(base).
template<viewable_range R> requires (!common_range<R> && constructible_­from<V, views::all_t<R>>) constexpr explicit common_view(R&& r);
Effects: Initializes base_­ with views​::​all(std​::​forward<R>(r)).

24.7.14 Reverse view [range.reverse]

24.7.14.1 Overview [range.reverse.overview]

reverse_­view takes a bidirectional view and produces another view that iterates the same elements in reverse order.
The name views​::​reverse denotes a range adaptor object ([range.adaptor.object]).
Given a subexpression E, the expression views​::​reverse(E) is expression-equivalent to:
  • If the type of E is a (possibly cv-qualified) specialization of reverse_­view, equivalent to E.base().
  • Otherwise, if the type of E is cv-qualified
    subrange<reverse_iterator<I>, reverse_iterator<I>, K>
    
    for some iterator type I and value K of type subrange_­kind,
    • if K is subrange_­kind​::​sized, equivalent to:
      subrange<I, I, K>(E.end().base(), E.begin().base(), E.size())
      
    • otherwise, equivalent to:
      subrange<I, I, K>(E.end().base(), E.begin().base())
      
    However, in either case E is evaluated only once.
  • Otherwise, equivalent to reverse_­view{E}.
Example
:
vector<int> is {0,1,2,3,4};
reverse_view rv {is};
for (int i : rv)
  cout << i << ' '; // prints: 4 3 2 1 0
— end example
 ]

24.7.14.2 Class template reverse_­view [range.reverse.view]

namespace std::ranges {
  template<view V>
    requires bidirectional_range<V>
  class reverse_view : public view_interface<reverse_view<V>> {
  private:
    V base_ = V();  // exposition only
  public:
    reverse_view() = default;

    constexpr explicit reverse_view(V r);

    constexpr V base() const& requires copy_constructible<V> { return base_; }
    constexpr V base() && { return std::move(base_); }

    constexpr reverse_iterator<iterator_t<V>> begin();
    constexpr reverse_iterator<iterator_t<V>> begin() requires common_range<V>;
    constexpr auto begin() const requires common_range<const V>;

    constexpr reverse_iterator<iterator_t<V>> end();
    constexpr auto end() const requires common_range<const V>;

    constexpr auto size() requires sized_range<V> {
      return ranges::size(base_);
    }
    constexpr auto size() const requires sized_range<const V> {
      return ranges::size(base_);
    }
  };

  template<class R>
    reverse_view(R&&) -> reverse_view<views::all_t<R>>;
}
constexpr explicit reverse_view(V base);
Effects: Initializes base_­ with std​::​move(base).
constexpr reverse_iterator<iterator_t<V>> begin();
Returns:
make_reverse_iterator(ranges::next(ranges::begin(base_), ranges::end(base_)))
Remarks: In order to provide the amortized constant time complexity required by the range concept, this function caches the result within the reverse_­view for use on subsequent calls.
constexpr reverse_iterator<iterator_t<V>> begin() requires common_range<V>; constexpr auto begin() const requires common_range<const V>;
Effects: Equivalent to: return make_­reverse_­iterator(ranges​::​end(base_­));
constexpr reverse_iterator<iterator_t<V>> end(); constexpr auto end() const requires common_range<const V>;
Effects: Equivalent to: return make_­reverse_­iterator(ranges​::​begin(base_­));

24.7.15 Elements view [range.elements]

24.7.15.1 Overview [range.elements.overview]

elements_­view takes a view of tuple-like values and a size_­t, and produces a view with a value-type of the element of the adapted view's value-type.
The name views​::​elements<N> denotes a range adaptor object ([range.adaptor.object]).
Given a subexpression E and constant expression N, the expression views​::​elements<N>(E) is expression-equivalent to elements_­view<views​::​all_­t<decltype((E))>, N>{E}.
Example
:
auto historical_figures = map{
  {"Lovelace"sv, 1815},
  {"Turing"sv, 1912},
  {"Babbage"sv, 1791},
  {"Hamilton"sv, 1936}
};

auto names = historical_figures | views::elements<0>;
for (auto&& name : names) {
  cout << name << ' ';          // prints Babbage Hamilton Lovelace Turing 
}

auto birth_years = historical_figures | views::elements<1>;
for (auto&& born : birth_years) {
  cout << born << ' ';          // prints 1791 1936 1815 1912 
}
— end example
 ]
keys_­view is an alias for elements_­view<views​::​all_­t<R>, 0>, and is useful for extracting keys from associative containers.
Example
:
auto names = keys_view{historical_figures};
for (auto&& name : names) {
  cout << name << ' ';          // prints Babbage Hamilton Lovelace Turing 
}
— end example
 ]
values_­view is an alias for elements_­view<views​::​all_­t<R>, 1>, and is useful for extracting values from associative containers.
Example
:
auto is_even = [](const auto x) { return x % 2 == 0; };
cout << ranges::count_if(values_view{historical_figures}, is_even);     // prints 2
— end example
 ]

24.7.15.2 Class template elements_­view [range.elements.view]

namespace std::ranges {
  template<class T, size_t N>
  concept has-tuple-element =                   // exposition only
    requires(T t) {
      typename tuple_size<T>::type;
      requires N < tuple_size_v<T>;
      typename tuple_element_t<N, T>;
      { get<N>(t) } -> convertible_to<const tuple_element_t<N, T>&>;
    };


  template<input_range V, size_t N>
    requires view<V> && has-tuple-element<range_value_t<V>, N> &&
             has-tuple-element<remove_reference_t<range_reference_t<V>>, N>
  class elements_view : public view_interface<elements_view<V, N>> {
  public:
    elements_view() = default;
    constexpr explicit elements_view(V base);

    constexpr V base() const& requires copy_constructible<V> { return base_; }
    constexpr V base() && { return std::move(base_); }

    constexpr auto begin() requires (!simple-view<V>)
    { return iterator<false>(ranges::begin(base_)); }

    constexpr auto begin() const requires simple-view<V>
    { return iterator<true>(ranges::begin(base_)); }

    constexpr auto end()
    { return sentinel<false>{ranges::end(base_)}; }

    constexpr auto end() requires common_range<V>
    { return iterator<false>{ranges::end(base_)}; }

    constexpr auto end() const requires range<const V>
    { return sentinel<true>{ranges::end(base_)}; }

    constexpr auto end() const requires common_range<const V>
    { return iterator<true>{ranges::end(base_)}; }

    constexpr auto size() requires sized_range<V>
    { return ranges::size(base_); }

    constexpr auto size() const requires sized_range<const V>
    { return ranges::size(base_); }

  private:
    // [range.elements.iterator], class template elements_­view​::​iterator
    template<bool> struct iterator;                     // exposition only
    // [range.elements.sentinel], class template elements_­view​::​sentinel
    template<bool> struct sentinel;                     // exposition only
    V base_ = V();                                      // exposition only
  };
}
constexpr explicit elements_view(V base);
Effects: Initializes base_­ with std​::​move(base).

24.7.15.3 Class template elements_­view​::​iterator [range.elements.iterator]

namespace std::ranges {
  template<input_range V, size_t N>
    requires view<V> && has-tuple-element<range_value_t<V>, N> &&
             has-tuple-element<remove_reference_t<range_reference_t<V>>, N>
  template<bool Const>
  class elements_view<V, N>::iterator {                 // exposition only
    using Base = conditional_t<Const, const V, V>;      // exposition only

    iterator_t<Base> current_ = iterator_t<Base>();
  public:
    using iterator_category = typename iterator_traits<iterator_t<Base>>::iterator_category;
    using value_type = remove_cvref_t<tuple_element_t<N, range_value_t<Base>>>;
    using difference_type = range_difference_t<Base>;

    iterator() = default;
    constexpr explicit iterator(iterator_t<Base> current);
    constexpr iterator(iterator<!Const> i)
      requires Const && convertible_to<iterator_t<V>, iterator_t<Base>>;

    constexpr iterator_t<Base> base() const&
      requires copyable<iterator_t<Base>>;
    constexpr iterator_t<Base> base() &&;

    constexpr decltype(auto) operator*() const
    { return get<N>(*current_); }

    constexpr iterator& operator++();
    constexpr void operator++(int) requires (!forward_range<Base>);
    constexpr iterator operator++(int) requires forward_range<Base>;

    constexpr iterator& operator--() requires bidirectional_range<Base>;
    constexpr iterator operator--(int) requires bidirectional_range<Base>;

    constexpr iterator& operator+=(difference_type x)
      requires random_access_range<Base>;
    constexpr iterator& operator-=(difference_type x)
      requires random_access_range<Base>;

    constexpr decltype(auto) operator[](difference_type n) const
      requires random_access_range<Base>
    { return get<N>(*(current_ + n)); }

    friend constexpr bool operator==(const iterator& x, const iterator& y)
      requires equality_comparable<iterator_t<Base>>;

    friend constexpr bool operator<(const iterator& x, const iterator& y)
      requires random_access_range<Base>;
    friend constexpr bool operator>(const iterator& x, const iterator& y)
      requires random_access_range<Base>;
    friend constexpr bool operator<=(const iterator& y, const iterator& y)
      requires random_access_range<Base>;
    friend constexpr bool operator>=(const iterator& x, const iterator& y)
      requires random_access_range<Base>;
    friend constexpr auto operator<=>(const iterator& x, const iterator& y)
      requires random_access_range<Base> && three_way_comparable<iterator_t<Base>>;

    friend constexpr iterator operator+(const iterator& x, difference_type y)
      requires random_access_range<Base>;
    friend constexpr iterator operator+(difference_type x, const iterator& y)
      requires random_access_range<Base>;
    friend constexpr iterator operator-(const iterator& x, difference_type y)
      requires random_access_range<Base>;
    friend constexpr difference_type operator-(const iterator& x, const iterator& y)
      requires random_access_range<Base>;
  };
}
constexpr explicit iterator(iterator_t<Base> current);
Effects: Initializes current_­ with std​::​move(current).
constexpr iterator(iterator<!Const> i) requires Const && convertible_­to<iterator_t<V>, iterator_t<Base>>;
Effects: Initializes current_­ with std​::​move(i.current_­).
constexpr iterator_t<Base> base() const& requires copyable<iterator_t<Base>>;
Effects: Equivalent to: return current_­;
constexpr iterator_t<Base> base() &&;
Effects: Equivalent to: return std​::​move(current_­);
constexpr iterator& operator++();
Effects: Equivalent to:
++current_;
return *this;
constexpr void operator++(int) requires (!forward_­range<Base>);
Effects: Equivalent to: ++current_­.
constexpr iterator operator++(int) requires forward_­range<Base>;
Effects: Equivalent to:
auto temp = *this;
++current_;
return temp;
constexpr iterator& operator--() requires bidirectional_­range<Base>;
Effects: Equivalent to:
--current_;
return *this;
constexpr iterator operator--(int) requires bidirectional_­range<Base>;
Effects: Equivalent to:
auto temp = *this;
--current_;
return temp;
constexpr iterator& operator+=(difference_type n); requires random_­access_­range<Base>;
Effects: Equivalent to:
current_ += n;
return *this;
constexpr iterator& operator-=(difference_type n) requires random_­access_­range<Base>;
Effects: Equivalent to:
current_ -= n;
return *this;
friend constexpr bool operator==(const iterator& x, const iterator& y) requires equality_comparable<Base>;
Effects: Equivalent to: return x.current_­ == y.current_­;
friend constexpr bool operator<(const iterator& x, const iterator& y) requires random_­access_­range<Base>;
Effects: Equivalent to: return x.current_­ < y.current_­;
friend constexpr bool operator>(const iterator& x, const iterator& y) requires random_­access_­range<Base>;
Effects: Equivalent to: return y < x;
friend constexpr bool operator<=(const iterator& x, const iterator& y) requires random_­access_­range<Base>;
Effects: Equivalent to: return !(y < x);
friend constexpr bool operator>=(const iterator& x, const iterator& y) requires random_­access_­range<Base>;
Effects: Equivalent to: return !(x < y);
friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires random_­access_­range<Base> && three_­way_­comparable<iterator_t<Base>>;
Effects: Equivalent to: return x.current_­ <=> y.current_­;
friend constexpr iterator operator+(const iterator& x, difference_type y) requires random_­access_­range<Base>;
Effects: Equivalent to: return iterator{x} += y;
friend constexpr iterator operator+(difference_type x, const iterator& y) requires random_­access_­range<Base>;
Effects: Equivalent to: return y + x;
constexpr iterator operator-(const iterator& x, difference_type y) requires random_­access_­range<Base>;
Effects: Equivalent to: return iterator{x} -= y;
constexpr difference_type operator-(const iterator& x, const iterator& y) requires random_­access_­range<Base>;
Effects: Equivalent to: return x.current_­ - y.current_­;

24.7.15.4 Class template elements_­view​::​sentinel [range.elements.sentinel]

namespace std::ranges {
  template<input_range V, size_t N>
    requires view<V> && has-tuple-element<range_value_t<V>, N> &&
             has-tuple-element<remove_reference_t<range_reference_t<V>>, N>
  template<bool Const>
  class elements_view<V, N>::sentinel {                 // exposition only
  private:
    using Base = conditional_t<Const, const V, V>;      // exposition only
    sentinel_t<Base> end_ = sentinel_t<Base>();         // exposition only
  public:
    sentinel() = default;
    constexpr explicit sentinel(sentinel_t<Base> end);
    constexpr sentinel(sentinel<!Const> other)
      requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;

    constexpr sentinel_t<Base> base() const;

    friend constexpr bool operator==(const iterator<Const>& x, const sentinel& y);

    friend constexpr range_difference_t<Base>
      operator-(const iterator<Const>& x, const sentinel& y)
        requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;

    friend constexpr range_difference_t<Base>
      operator-(const sentinel& x, const iterator<Const>& y)
        requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
  };
}
constexpr explicit sentinel(sentinel_t<Base> end);
Effects: Initializes end_­ with end.
constexpr sentinel(sentinel<!Const> other) requires Const && convertible_­to<sentinel_t<V>, sentinel_t<Base>>;
Effects: Initializes end_­ with std​::​move(other.end_­).
constexpr sentinel_t<Base> base() const;
Effects: Equivalent to: return end_­;
friend constexpr bool operator==(const iterator<Const>& x, const sentinel& y);
Effects: Equivalent to: return x.current_­ == y.end_­;
friend constexpr range_difference_t<Base> operator-(const iterator<Const>& x, const sentinel& y) requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
Effects: Equivalent to: return x.current_­ - y.end_­;
friend constexpr range_difference_t<Base> operator-(const sentinel& x, const iterator<Const>& y) requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
Effects: Equivalent to: return x.end_­ - y.current_­;