# Standard library header <ranges>

From cppreference.com
< cpp‎ | header

This header is part of the ranges library.

### Namespace aliases

namespace std { namespace view = ranges::view; } |  |

The namespace alias `std::view` is provided as a shorthand for `std::ranges::view`.

### Concepts

##### Range concepts

Defined in namespace `std::ranges`
Range | specifies that a type is a range, that is, it provides a `begin` iterator and an `end` sentinel (concept)
SizedRange | specifies that a range knows its size in constant time (concept)
View | specifies that a range is a view, that is, it has constant time copy/move/assignment (concept)
InputRange | specifies a range whose iterator type satisfies `InputIterator` (concept)
OutputRange | specifies a range whose iterator type satisfies `OutputIterator` (concept)
ForwardRange | specifies a range whose iterator type satisfies `ForwardIterator` (concept)
BidirectionalRange | specifies a range whose iterator type satisfies `BidirectionalIterator` (concept)
RandomAccessRange | specifies a range whose iterator type satisfies `RandomAccessIterator` (concept)
ContiguousRange | specifies a range whose iterator type satisfies `ContiguousIterator` (concept)
CommonRange | specifies that a range has identical iterator and sentinel types (concept)
ViewableRange | specifies the requirements for a `Range` to be safely convertible to a `View` (concept)

### Classes

##### Range primitives

Defined in namespace `std::ranges`
iterator_tsentinel_t | obtains the iterator and sentinel types of a range (alias template)

##### Views

Defined in namespace `std::ranges`
view_interface | helper class template for defining `View`s, using the curiously recurring template pattern (class template)
subrange | combines an iterator-sentinel pair into a `View` (class template)

##### Dangling iterator handling

Defined in namespace `std::ranges`
dangling | a placeholder type indicating that an iterator or a `subrange` should not be returned since it would be dangling (class)
safe_iterator_tsafe_subrange_t | obtains iterator type or `subrange` type of a `Range` which also models `__ForwardingRange` (alias template)

##### Factories

Defined in namespace `std::ranges`
empty_viewview::empty | an empty `View` with no elements (class template) (variable template)
single_viewview::single | a `View` that contains a single element of a specified value (class template) (customization point object)
iota_viewview::iota | a `View` consisting of a sequence generated by repeatedly incrementing an initial value (class template) (customization point object)
view::counted | creates a subrange from an iterator and a count (customization point object)

##### Adaptors

Defined in namespace `std::ranges`
all_viewview::all | a `View` that includes all elements of a `Range` (alias template) (range adaptor object)
ref_view | a `View` of the elements of some other `Range` (class template)
filter_viewview::filter | a `View` that consists of the elements of a `Range` that satisfies a predicate (class template) (range adaptor object)
transform_viewview::transform | a `View` of a sequence that applies a transformation function to each element (class template) (range adaptor object)
take_viewview::take | a `View` consisting of the first N elements of another `View` (class template) (range adaptor object)
join_viewview::join | a `View` consisting of the sequence obtained from flattening a `View` of `Range`s (class template) (range adaptor object)
split_viewview::split | a `View` over the subranges obtained from splitting another `View` using a delimiter (class template) (range adaptor object)
common_viewview::common | converts a `View` into a `CommonRange` (class template) (range adaptor object)
reverse_viewview::reverse | a `View` that iterates over the elements of another bidirectional view in reverse order (class template) (range adaptor object)

### Customization point objects

##### Range access

Defined in namespace `std::ranges`
begincbegin | returns an iterator to the beginning of a range (customization point object)
endcend | returns an iterator to the end of a range (customization point object)
rbegincrbegin | returns a reverse iterator to a range (customization point object)
rendcrend | returns a reverse end iterator to a range (customization point object)
size | obtains the size of a range whose size can be calculated in constant time (customization point object)
empty | checks whether a range is empty (customization point object)
datacdata | obtains a pointer to the beginning of a contiguous range (customization point object)

### Synopsis

    #include <initializer_list>
    #include <iterator>

    namespace std::ranges {
      inline namespace /* unspecified */ {
        // 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 */ empty = /* unspecified */;
        inline constexpr /* unspecified */ data = /* unspecified */;
        inline constexpr /* unspecified */ cdata = /* unspecified */;
      }

      // ranges
      template<class T>
        using iterator_t = decltype(ranges::begin(declval<T&>()));

      template<class T>
        using sentinel_t = decltype(ranges::end(declval<T&>()));

      template<class T>
        concept Range = /* see definition */;

      // sized ranges
      template<class>
        inline constexpr bool disable_sized_range = false;

      template<class T>
        concept SizedRange = /* see definition */;

      // views
      template<class T>
        inline constexpr bool enable_view = /* see definition */;

      struct view_base { };

      template<class T>
        concept View = /* see definition */;

      // other range refinements
      template<class R, class T>
        concept OutputRange = /* see definition */;

      template<class T>
        concept InputRange = /* see definition */;

      template<class T>
        concept ForwardRange = /* see definition */;

      template<class T>
        concept BidirectionalRange = /* see definition */;

      template<class T>
        concept RandomAccessRange = /* see definition */;

      template<class T>
        concept ContiguousRange = /* see definition */;

      template<class T>
        concept CommonRange = /* see definition */;

      template<class T>
        concept ViewableRange = /* see definition */;

      // class template view_interface
      template<class D>
        requires is_class_v<D> && Same<D, remove_cv_t<D>>
      class view_interface;

      // sub-ranges
      enum class subrange_kind : bool { unsized, sized };

      template<Iterator I, Sentinel<I> S = I, subrange_kind K = /* see definition */>
        requires (K == subrange_kind::sized || !SizedSentinel<S, I>)
      class subrange;

      // dangling iterator handling
      struct dangling;

      template<Range R>
        using safe_iterator_t = conditional_t<__ForwardingRange<R>, iterator_t<R>, dangling>;

      template<Range R>
        using safe_subrange_t =
          conditional_t<__ForwardingRange<R>, subrange<iterator_t<R>>, dangling>;

      // empty view
      template<class T>
        requires is_object_v<T>
      class empty_view;

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

      // single view
      template<CopyConstructible T>
        requires is_object_v<T>
      class single_view;

      namespace view { inline constexpr /* unspecified */ single = /* unspecified */; }

      // iota view
      template<WeaklyIncrementable W, Semiregular Bound = unreachable_sentinel_t>
        requires __WeaklyEqualityComparableWith<W, Bound>
      class iota_view;

      namespace view { inline constexpr /* unspecified */ iota = /* unspecified */; }

      // all view
      namespace view { inline constexpr /* unspecified */ all = /* unspecified */; }

      template<ViewableRange R>
        using all_view = decltype(view::all(declval<R>()));

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

      // filter view
      template<InputRange V, IndirectUnaryPredicate<iterator_t<V>> Pred>
        requires View<V> && is_object_v<Pred>
      class filter_view;

      namespace view { inline constexpr /* unspecified */ filter = /* unspecified */; }

      // transform view
      template<InputRange V, CopyConstructible F>
        requires View<V> && is_object_v<F> &&
                 RegularInvocable<F&, iter_reference_t<iterator_t<V>>>
      class transform_view;

      namespace view { inline constexpr /* unspecified */ transform = /* unspecified */; }

      // take view
      template<View> class take_view;

      namespace view { inline constexpr /* unspecified */ take = /* unspecified */; }

      // join view
      template<InputRange V>
        requires View<V> && InputRange<iter_reference_t<iterator_t<V>>> &&
                 (is_reference_v<iter_reference_t<iterator_t<V>>> ||
                  View<iter_value_t<iterator_t<V>>>)
      class join_view;

      namespace view { inline constexpr /* unspecified */ join = /* unspecified */; }

      // split view
      template<class R>
        concept __TinyRange = /* see definition */;   // exposition only

      template<InputRange V, ForwardRange Pattern>
        requires View<V> && View<Pattern> &&
                 IndirectlyComparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
                 (ForwardRange<V> || __TinyRange<Pattern>)
      class split_view;

      namespace view { inline constexpr /* unspecified */ split = /* unspecified */; }

      // counted view
      namespace view { inline constexpr /* unspecified */ counted = /* unspecified */; }

      // common view
      template<View V>
        requires (!CommonRange<V>)
      class common_view;

      namespace view { inline constexpr /* unspecified */ common = /* unspecified */; }

      // reverse view
      template<View V>
        requires BidirectionalRange<V>
      class reverse_view;

      namespace view { inline constexpr /* unspecified */ reverse = /* unspecified */; }
    }

    namespace std {
      namespace view = ranges::view;

      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;
      };
    }

#### Concept `Range`

    namespace std::ranges {
      template<class T>
        concept __RangeImpl =          // exposition only
          requires(T&& t) {
            ranges::begin(std::forward<T>(t));// sometimes equality-preserving (see definition)
            ranges::end(std::forward<T>(t));
          };

      template<class T>
        concept Range = __RangeImpl<T&>;

      template<class T>
        concept __ForwardingRange =    // exposition only
          Range<T> && __RangeImpl<T>;
    }

#### Concept `SizedRange`

    namespace std::ranges {
      template<class T>
        concept SizedRange =
          Range<T> &&
          !disable_sized_range<remove_cvref_t<T>> &&
          requires(T& t) { ranges::size(t); };
    }

#### Concept `View`

    namespace std::ranges {
      template<class T>
        inline constexpr bool enable_view = /* see definition */;

      template<class T>
        concept View =
          Range<T> && Semiregular<T> && enable_view<T>;
    }

#### Concept `OutputRange`

    namespace std::ranges {
      template<class R, class T>
        concept OutputRange =
          Range<R> && OutputIterator<iterator_t<R>, T>;
    }

#### Concept `InputRange`

    namespace std::ranges {
      template<class T>
        concept InputRange =
          Range<T> && InputIterator<iterator_t<T>>;
    }

#### Concept `ForwardRange`

    namespace std::ranges {
      template<class T>
        concept ForwardRange =
          InputRange<T> && ForwardIterator<iterator_t<T>>;
    }

#### Concept `BidirectionalRange`

    namespace std::ranges {
      template<class T>
        concept BidirectionalRange =
          ForwardRange<T> && BidirectionalIterator<iterator_t<T>>;
    }

#### Concept `RandomAccessRange`

    namespace std::ranges {
      template<class T>
        concept RandomAccessRange =
          BidirectionalRange<T> && RandomAccessIterator<iterator_t<T>>;
    }

#### Concept `ContiguousRange`

    namespace std::ranges {
      template<class T>
        concept ContiguousRange =
         RandomAccessRange<T> && ContiguousIterator<iterator_t<T>> &&
          requires(T& t) {
            { ranges::data(t) } -> Same<add_pointer_t<iter_reference_t<iterator_t<T>>>>;
          };
    }

#### Concept `CommonRange`

    namespace std::ranges {
      template<class T>
        concept CommonRange =
          Range<T> && Same<iterator_t<T>, sentinel_t<T>>;
    }

#### Concept `ViewableRange`

    namespace std::ranges {
      template<class T>
        concept ViewableRange =
          Range<T> && (__ForwardingRange<T> || View<decay_t<T>>);
    }

#### Helper concepts

    namespace std::ranges { // unspecified, for name lookup only
      template<class R>
        concept __SimpleView =                        // exposition only
          View<R> && Range<const R> &&
          Same<iterator_t<R>, iterator_t<const R>> &&
          Same<sentinel_t<R>, sentinel_t<const R>>;

      template<InputIterator I>
        concept __HasArrow =                          // exposition only
          is_pointer_v<I> || requires(I i) { i.operator->(); };

      template<class T, class U>
        concept __NotSameAs =                         // exposition only
          !Same<remove_cvref_t<T>, remove_cvref_t<U>>;

      template<class I>
        concept _Decrementable =                      // exposition only
          Incrementable<I> && requires(I i) {
            { --i } -> Same<I&>;
            { i-- } -> Same<I>;
          };

      template<class I>
        concept _Advanceable =                        // exposition only
          _Decrementable<I> && StrictTotallyOrdered<I> &&
          requires(I i, const I j, const iter_difference_t<I> n) {
            { i += n } -> Same<I&>;
            { i -= n } -> Same<I&>;
            { j +  n } -> Same<I>;
            { n +  j } -> Same<I>;
            { j -  n } -> Same<I>;
            { j -  j } -> Same<iter_difference_t<I>>;
          };
    }

Note: These names are only for exposition, they are not part of the interface.

#### Class template std::ranges::view_interface

    namespace std::ranges {
      template<class D>
        requires is_class_v<D> && Same<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 ForwardRange<D> {
          return ranges::begin(derived()) == ranges::end(derived());
        }
        constexpr bool empty() const requires ForwardRange<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 ContiguousIterator<iterator_t<D>> {
          return ranges::empty(derived()) ? nullptr : addressof(*ranges::begin(derived()));
        }
        constexpr auto data() const
          requires Range<const D> && ContiguousIterator<iterator_t<const D>> {
            return ranges::empty(derived()) ? nullptr : addressof(*ranges::begin(derived()));
          }

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

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

        constexpr decltype(auto) back() requires BidirectionalRange<D> && CommonRange<D>;
        constexpr decltype(auto) back() const
          requires BidirectionalRange<const D> && CommonRange<const D>;

        template<RandomAccessRange R = D>
          constexpr decltype(auto) operator[](iter_difference_t<iterator_t<R>> n) {
            return ranges::begin(derived())[n];
          }
        template<RandomAccessRange R = const D>
          constexpr decltype(auto) operator[](iter_difference_t<iterator_t<R>> n) const {
            return ranges::begin(derived())[n];
          }
      };
    }

#### Class template std::ranges::subrange

    namespace std::ranges {
      template<class T>
        concept __PairLike =                                // exposition only
          !is_reference_v<T> && requires(T t) {
            typename tuple_size<T>::type;   // ensures tuple_size<T> is complete
            requires DerivedFrom<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) } -> const tuple_element_t<0, T>&;
            { get<1>(t) } -> const tuple_element_t<1, T>&;
          };

      template<class T, class U, class V>
        concept __PairLikeConvertibleTo =                   // exposition only
          !Range<T> && __PairLike<remove_reference_t<T>> &&
          requires(T&& t) {
            { get<0>(std::forward<T>(t)) } -> ConvertibleTo<U>;
            { get<1>(std::forward<T>(t)) } -> ConvertibleTo<V>;
          };

      template<class T, class U, class V>
        concept __PairLikeConvertibleFrom =                 // exposition only
          !Range<T> && __PairLike<T> && Constructible<T, U, V>;

      template<class T>
        concept __IteratorSentinelPair =                    // exposition only
          !Range<T> && __PairLike<T> &&
          Sentinel<tuple_element_t<1, T>, tuple_element_t<0, T>>;

      template<Iterator I, Sentinel<I> S = I, subrange_kind K =
          SizedSentinel<S, I> ? subrange_kind::sized : subrange_kind::unsized>
        requires (K == subrange_kind::sized || !SizedSentinel<S, I>)
      class subrange : public view_interface<subrange<I, S, K>> {
      private:
        static constexpr bool StoreSize =                   // exposition only
          K == subrange_kind::sized && !SizedSentinel<S, I>;
        I begin_ = I();                                     // exposition only
        S end_ = S();                                       // exposition only
        iter_difference_t<I> size_ = 0;                     // exposition only; present only
                                                            // when StoreSize is true
      public:
        subrange() = default;

        constexpr subrange(I i, S s) requires (!StoreSize);

        constexpr subrange(I i, S s, iter_difference_t<I> n)
          requires (K == subrange_kind::sized);

        template<__NotSameAs<subrange> R>
          requires __ForwardingRange<R> &&
            ConvertibleTo<iterator_t<R>, I> && ConvertibleTo<sentinel_t<R>, S>
        constexpr subrange(R&& r) requires (!StoreSize || SizedRange<R>);

        template<__ForwardingRange R>
          requires ConvertibleTo<iterator_t<R>, I> && ConvertibleTo<sentinel_t<R>, S>
        constexpr subrange(R&& r, iter_difference_t<I> n)
          requires (K == subrange_kind::sized)
            : subrange{ranges::begin(r), ranges::end(r), n}
        {}

        template<__NotSameAs<subrange> PairLike>
          requires __PairLikeConvertibleTo<PairLike, I, S>
        constexpr subrange(PairLike&& r) requires (!StoreSize)
          : subrange{std::get<0>(std::forward<PairLike>(r)),
                     std::get<1>(std::forward<PairLike>(r))}
        {}

        template<__PairLikeConvertibleTo<I, S> PairLike>
        constexpr subrange(PairLike&& r, iter_difference_t<I> n)
          requires (K == subrange_kind::sized)
          : subrange{std::get<0>(std::forward<PairLike>(r)),
                     std::get<1>(std::forward<PairLike>(r)), n}
        {}

        template<__NotSameAs<subrange> PairLike>
          requires __PairLikeConvertibleFrom<PairLike, const I&, const S&>
        constexpr operator PairLike() const;

        constexpr I begin() const;
        constexpr S end() const;

        constexpr bool empty() const;
        constexpr iter_difference_t<I> size() const
          requires (K == subrange_kind::sized);

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

        friend constexpr I begin(subrange&& r) { return r.begin(); }
        friend constexpr S end(subrange&& r) { return r.end(); }
      };

      template<Iterator I, Sentinel<I> S>
        subrange(I, S, iter_difference_t<I>) -> subrange<I, S, subrange_kind::sized>;

      template<__IteratorSentinelPair P>
        subrange(P) -> subrange<tuple_element_t<0, P>, tuple_element_t<1, P>>;

      template<__IteratorSentinelPair P>
        subrange(P, iter_difference_t<tuple_element_t<0, P>>) ->
          subrange<tuple_element_t<0, P>, tuple_element_t<1, P>, subrange_kind::sized>;

      template<__ForwardingRange R>
        subrange(R&&) ->
          subrange<iterator_t<R>, sentinel_t<R>,
                   (SizedRange<R> || SizedSentinel<sentinel_t<R>, iterator_t<R>>)
                     ? subrange_kind::sized : subrange_kind::unsized>;

      template<__ForwardingRange R>
        subrange(R&&, iter_difference_t<iterator_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);
    }

    namespace std {
      using ranges::get;
    }

#### Class std::ranges::dangling

    namespace std::ranges {
      struct dangling {
        constexpr dangling() noexcept = default;
        template<class... Args>
          constexpr dangling(Args&&...) noexcept { }
      };
    }

#### Class template std::ranges::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 ptrdiff_t size() noexcept { return 0; }
        static constexpr bool empty() noexcept { return true; }

        friend constexpr T* begin(empty_view) noexcept { return nullptr; }
        friend constexpr T* end(empty_view) noexcept { return nullptr; }
      };
    }

#### Class template std::ranges::empty_view

    namespace std::ranges {
      template<CopyConstructible T>
        requires is_object_v<T>
      class single_view : public view_interface<single_view<T>> {
      private:
        semiregular<T> value_;      // exposition only
      public:
        single_view() = default;
        constexpr explicit single_view(const T& t);
        constexpr explicit single_view(T&& t);
        template<class... Args>
          requires Constructible<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 ptrdiff_t size() noexcept;
        constexpr T* data() noexcept;
        constexpr const T* data() const noexcept;
      };
    }

#### Class template std::ranges::iota_view

    namespace std::ranges {
      template<class I>
        concept _Decrementable =    // exposition only
          /* see definition */;
      template<class I>
        concept _Advanceable =      // exposition only
          /* see definition */;

      template<WeaklyIncrementable W, Semiregular Bound = unreachable_sentinel_t>
        requires __WeaklyEqualityComparableWith<W, Bound>
      class iota_view : public view_interface<iota_view<W, Bound>> {
      private:
        // class iota_view​::​iterator
        struct iterator;            // exposition only
        // 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 iterator begin() const;
        constexpr sentinel end() const;
        constexpr iterator end() const requires Same<W, Bound>;

        constexpr auto size() const
          requires (Same<W, Bound> && _Advanceable<W>) ||
                   (Integral<W> && Integral<Bound>) ||
                   SizedSentinel<Bound, W>
        { return bound_ - value_; }
      };

      template<class W, class Bound>
        requires (!Integral<W> || !Integral<Bound> || is_signed_v<W> == is_signed_v<Bound>)
      iota_view(W, Bound) -> iota_view<W, Bound>;
    }

#### Class std::ranges::iota_view::iterator

    namespace std::ranges {
      template<class W, class Bound>
      struct iota_view<W, Bound>::iterator {
      private:
        W value_ = W();             // exposition only
      public:
        using iterator_category = /* see definition */;
        using value_type = W;
        using difference_type = iter_difference_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 EqualityComparable<W>;
        friend constexpr bool operator!=(const iterator& x, const iterator& y)
          requires EqualityComparable<W>;

        friend constexpr bool operator<(const iterator& x, const iterator& y)
          requires StrictTotallyOrdered<W>;
        friend constexpr bool operator>(const iterator& x, const iterator& y)
          requires StrictTotallyOrdered<W>;
        friend constexpr bool operator<=(const iterator& x, const iterator& y)
          requires StrictTotallyOrdered<W>;
        friend constexpr bool operator>=(const iterator& x, const iterator& y)
          requires StrictTotallyOrdered<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>;
      };
    }

#### Class std::ranges::iota_view::sentinel

    namespace std::ranges {
      template<class W, class 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 bool operator==(const sentinel& x, const iterator& y);
        friend constexpr bool operator!=(const iterator& x, const sentinel& y);
        friend constexpr bool operator!=(const sentinel& x, const iterator& y);
      };
    }

#### Class template std::ranges::ref_view

    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<__NotSameAs<ref_view> T>
          requires /* see definition */
        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 SizedRange<R>
        { return ranges::size(*r_); }

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

        friend constexpr iterator_t<R> begin(ref_view r)
        { return r.begin(); }

        friend constexpr sentinel_t<R> end(ref_view r)
        { return r.end(); }
      };
      template<class R>
        ref_view(R&) -> ref_view<R>;
    }

#### Class template std::ranges::filter_view

    namespace std::ranges {
      template<InputRange V, IndirectUnaryPredicate<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<Pred> pred_;    // exposition only

        // class filter_view​::​iterator
        class iterator;             // exposition only
        // class filter_view​::​sentinel
        class sentinel;             // exposition only

      public:
        filter_view() = default;
        constexpr filter_view(V base, Pred pred);
        template<InputRange R>
          requires ViewableRange<R> && Constructible<V, all_view<R>>
        constexpr filter_view(R&& r, Pred pred);

        constexpr V base() const;

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

      template<class R, class Pred>
        filter_view(R&&, Pred) -> filter_view<all_view<R>, Pred>;
    }

#### Class std::ranges::filter_view::iterator

    namespace std::ranges {
      template<class V, class 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 definition */;
        using iterator_category = /* see definition */;
        using value_type        = iter_value_t<iterator_t<V>>;
        using difference_type   = iter_difference_t<iterator_t<V>>;

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

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

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

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

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

        friend constexpr iter_rvalue_reference_t<iterator_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 IndirectlySwappable<iterator_t<V>>;
      };
    }

#### Class std::ranges::filter_view::sentinel

    namespace std::ranges {
      template<class V, class 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);
        friend constexpr bool operator==(const sentinel& x, const iterator& y);
        friend constexpr bool operator!=(const iterator& x, const sentinel& y);
        friend constexpr bool operator!=(const sentinel& x, const iterator& y);
      };
    }

#### Class template std::ranges::transform_view

    namespace std::ranges {
      template<InputRange V, CopyConstructible F>
        requires View<V> && is_object_v<F> &&
                 RegularInvocable<F&, iter_reference_t<iterator_t<V>>>
      class transform_view : public view_interface<transform_view<V, F>> {
      private:
        // class template transform_view​::​iterator
        template<bool> struct iterator;             // exposition only
        // class template transform_view​::​sentinel
        template<bool> struct sentinel;             // exposition only

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

      public:
        transform_view() = default;
        constexpr transform_view(V base, F fun);
        template<InputRange R>
          requires ViewableRange<R> && Constructible<V, all_view<R>>
        constexpr transform_view(R&& r, F fun);

        constexpr V base() const;

        constexpr iterator<false> begin();
        constexpr iterator<true> begin() const
          requires Range<const V> &&
                   RegularInvocable<const F&, iter_reference_t<iterator_t<const V>>>;

        constexpr sentinel<false> end();
        constexpr iterator<false> end() requires CommonRange<V>;
        constexpr sentinel<true> end() const
          requires Range<const V> &&
                   RegularInvocable<const F&, iter_reference_t<iterator_t<const V>>>;
        constexpr iterator<true> end() const
          requires CommonRange<const V> &&
                   RegularInvocable<const F&, iter_reference_t<iterator_t<const V>>>;

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

      template<class R, class F>
        transform_view(R&&, F) -> transform_view<all_view<R>, F>;
    }

#### Class template std::ranges::transform_view::iterator

    namespace std::ranges {
      template<class V, class F>
      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 definition */;
        using iterator_category = /* see definition */;
        using value_type        =
          remove_cvref_t<invoke_result_t<F&, iter_reference_t<iterator_t<Base>>>>;
        using difference_type   = iter_difference_t<iterator_t<Base>>;

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

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

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

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

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

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

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

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

        friend constexpr iterator operator-(iterator i, difference_type n)
          requires RandomAccessRange<Base>;
        friend constexpr difference_type operator-(const iterator& x, const iterator& y)
          requires RandomAccessRange<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 IndirectlySwappable<iterator_t<Base>>;
      };
    }

#### Class template std::ranges::transform_view::sentinel

    namespace std::ranges {
      template<class V, class F>
      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 && ConvertibleTo<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 bool operator==(const sentinel& x, const iterator<Const>& y);
        friend constexpr bool operator!=(const iterator<Const>& x, const sentinel& y);
        friend constexpr bool operator!=(const sentinel& x, const iterator<Const>& y);

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

#### Class template std::ranges::take_view

    namespace std::ranges {
      template<View V>
      class take_view : public view_interface<take_view<V>> {
      private:
        V base_ = V();                                      // exposition only
        iter_difference_t<iterator_t<V>> count_ = 0;        // exposition only
        // class template take_view​::​sentinel
        template<bool> struct sentinel;                     // exposition only
      public:
        take_view() = default;
        constexpr take_view(V base, iter_difference_t<iterator_t<V>> count);
        template<ViewableRange R>
          requires Constructible<V, all_view<R>>
        constexpr take_view(R&& r, iter_difference_t<iterator_t<V>> count);

        constexpr V base() const;

        constexpr auto begin() requires (!__SimpleView<V>) {
          if constexpr (SizedRange<V>) {
            if constexpr (RandomAccessRange<V>)
              return ranges::begin(base_);
            else
              return counted_iterator{ranges::begin(base_), size()};
          } else
            return counted_iterator{ranges::begin(base_), count_};
        }

        constexpr auto begin() const requires Range<const V> {
          if constexpr (SizedRange<const V>) {
            if constexpr (RandomAccessRange<const V>)
              return ranges::begin(base_);
            else
              return counted_iterator{ranges::begin(base_), size()};
          } else
            return counted_iterator{ranges::begin(base_), count_};
        }

        constexpr auto end() requires (!__SimpleView<V>) {
          if constexpr (SizedRange<V>) {
            if constexpr (RandomAccessRange<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 (SizedRange<const V>) {
            if constexpr (RandomAccessRange<const V>)
              return ranges::begin(base_) + size();
            else
              return default_sentinel;
          } else
            return sentinel<true>{ranges::end(base_)};
        }

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

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

      template<Range R>
        take_view(R&&, iter_difference_t<iterator_t<R>>)
          -> take_view<all_view<R>>;
    }

#### Class template std::ranges::take_view::sentinel

    namespace std::ranges {
      template<class 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 && ConvertibleTo<sentinel_t<V>, sentinel_t<Base>>;

        constexpr sentinel_t<Base> base() const;

        friend constexpr bool operator==(const sentinel& x, const CI& y);
        friend constexpr bool operator==(const CI& y, const sentinel& x);
        friend constexpr bool operator!=(const sentinel& x, const CI& y);
        friend constexpr bool operator!=(const CI& y, const sentinel& x);
      };
    }

#### Class template std::ranges::join_view

    namespace std::ranges {
      template<InputRange V>
        requires View<V> && InputRange<iter_reference_t<iterator_t<V>>> &&
                 (is_reference_v<iter_reference_t<iterator_t<V>>> ||
                  View<iter_value_t<iterator_t<V>>>)
      class join_view : public view_interface<join_view<V>> {
      private:
        using InnerRng =                    // exposition only
          iter_reference_t<iterator_t<V>>;
        // class template join_view​::​iterator
        template<bool Const>
          struct iterator;                  // exposition only
        // class template join_view​::​sentinel
        template<bool Const>
          struct sentinel;                  // exposition only

        V base_ = V();                      // exposition only
        all_view<InnerRng> inner_ =         // exposition only, present only when
          all_view<InnerRng>();              // !is_reference_v<InnerRng>
      public:
        join_view() = default;
        constexpr explicit join_view(V base);

        template<InputRange R>
          requires ViewableRange<R> && Constructible<V, all_view<R>>
        constexpr explicit join_view(R&& r);

        constexpr auto begin() {
          return iterator<__SimpleView<V>>{*this, ranges::begin(base_)};
        }

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

        constexpr auto end() {
          if constexpr (ForwardRange<V> &&
                        is_reference_v<InnerRng> && ForwardRange<InnerRng> &&
                        CommonRange<V> && CommonRange<InnerRng>)
            return iterator<__SimpleView<V>>{*this, ranges::end(base_)};
          else
            return sentinel<__SimpleView<V>>{*this};
        }

        constexpr auto end() const
        requires InputRange<const V> &&
                 is_reference_v<iter_reference_t<iterator_t<const V>>> {
          if constexpr (ForwardRange<const V> &&
                        is_reference_v<iter_reference_t<iterator_t<const V>>> &&
                        ForwardRange<iter_reference_t<iterator_t<const V>>> &&
                        CommonRange<const V> &&
                        CommonRange<iter_reference_t<iterator_t<const V>>>)
            return iterator<true>{*this, ranges::end(base_)};
          else
            return sentinel<true>{*this};
        }
      };

      template<class R>
        explicit join_view(R&&) -> join_view<all_view<R>>;
    }

#### Class template std::ranges::join_view::iterator

    namespace std::ranges {
    template<class 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<iter_reference_t<iterator_t<Base>>>;

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

        constexpr void satisfy();                                   // exposition only
      public:
        using iterator_concept  = /* see definition */;
        using iterator_category = /* see definition */;
        using value_type        =
          iter_value_t<iterator_t<iter_reference_t<iterator_t<Base>>>>;
        using difference_type   = /* see definition */;

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

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

        constexpr iterator_t<Base> operator->() const
          requires __HasArrow<iterator_t<Base>>;

        constexpr iterator& operator++();
        constexpr void operator++(int);
        constexpr iterator operator++(int)
          requires ref_is_glvalue && ForwardRange<Base> &&
                   ForwardRange<iter_reference_t<iterator_t<Base>>>;

        constexpr iterator& operator--()
          requires ref_is_glvalue && BidirectionalRange<Base> &&
                   BidirectionalRange<iter_reference_t<iterator_t<Base>>>;

        constexpr iterator operator--(int)
          requires ref_is_glvalue && BidirectionalRange<Base> &&
                   BidirectionalRange<iter_reference_t<iterator_t<Base>>>;

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

        friend constexpr bool operator!=(const iterator& x, const iterator& y)
          requires ref_is_glvalue && EqualityComparable<iterator_t<Base>> &&
                   EqualityComparable<iterator_t<iter_reference_t<iterator_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_)));
      };
    }

#### Class template std::ranges::join_view::sentinel

    namespace std::ranges {
      template<class 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 && ConvertibleTo<sentinel_t<V>, sentinel_t<Base>>;

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

#### Class template std::ranges::split_view

    namespace std::ranges {
      template<auto> struct __require_constant;     // exposition only

      template<class R>
      concept __TinyRange =                         // exposition only
        SizedRange<R> &&
        requires { typename __require_constant<remove_reference_t<R>::size()>; } &&
        (remove_reference_t<R>::size() <= 1);

      template<InputRange V, ForwardRange Pattern>
        requires View<V> && View<Pattern> &&
                 IndirectlyComparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
                 (ForwardRange<V> || __TinyRange<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
                                                    // !ForwardRange<V>
        // class template split_view​::​outer_iterator
        template<bool> struct outer_iterator;       // exposition only
        // 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<InputRange R, ForwardRange P>
          requires Constructible<V, all_view<R>> &&
                   Constructible<Pattern, all_view<P>>
        constexpr split_view(R&& r, P&& p);

        template<InputRange R>
          requires Constructible<V, all_view<R>> &&
                   Constructible<Pattern, single_view<iter_value_t<iterator_t<R>>>>
        constexpr split_view(R&& r, iter_value_t<iterator_t<R>> e);

        constexpr auto begin() {
          if constexpr (ForwardRange<V>)
            return outer_iterator<__SimpleView<V>>{*this, ranges::begin(base_)};
          else {
            current_ = ranges::begin(base_);
            return outer_iterator<false>{*this};
          }
        }

        constexpr auto begin() const requires ForwardRange<V> && ForwardRange<const V> {
          return outer_iterator<true>{*this, ranges::begin(base_)};
        }

        constexpr auto end() requires ForwardRange<V> && CommonRange<V> {
          return outer_iterator<__SimpleView<V>>{*this, ranges::end(base_)};
        }

        constexpr auto end() const {
          if constexpr (ForwardRange<V> && ForwardRange<const V> && CommonRange<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<all_view<R>, all_view<P>>;

      template<InputRange R>
        split_view(R&&, iter_value_t<iterator_t<R>>)
          -> split_view<all_view<R>, single_view<iter_value_t<iterator_t<R>>>>;
    }

#### Class template std::ranges::split_view::outer_iterator

    namespace std::ranges {
      template<class V, class 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
          iterator_t<Base>();                       // if V models ForwardRange

      public:
        using iterator_concept  =
          conditional_t<ForwardRange<Base>, forward_iterator_tag, input_iterator_tag>;
        using iterator_category = input_iterator_tag;
        struct value_type;
        using difference_type   = iter_difference_t<iterator_t<Base>>;

        outer_iterator() = default;
        constexpr explicit outer_iterator(Parent& parent)
          requires (!ForwardRange<Base>);
        constexpr outer_iterator(Parent& parent, iterator_t<Base> current)
          requires ForwardRange<Base>;
        constexpr outer_iterator(outer_iterator<!Const> i)
          requires Const && ConvertibleTo<iterator_t<V>, iterator_t<const V>>;

        constexpr value_type operator*() const;

        constexpr outer_iterator& operator++();
        constexpr decltype(auto) operator++(int) {
          if constexpr (ForwardRange<Base>) {
            auto tmp = *this;
            ++*this;
            return tmp;
          } else
            ++*this;
        }

        friend constexpr bool operator==(const outer_iterator& x, const outer_iterator& y)
          requires ForwardRange<Base>;
        friend constexpr bool operator!=(const outer_iterator& x, const outer_iterator& y)
          requires ForwardRange<Base>;

        friend constexpr bool operator==(const outer_iterator& x, default_sentinel_t);
        friend constexpr bool operator==(default_sentinel_t, const outer_iterator& x);
        friend constexpr bool operator!=(const outer_iterator& x, default_sentinel_t y);
        friend constexpr bool operator!=(default_sentinel_t y, const outer_iterator& x);
      };
    }

#### Class std::ranges::split_view::outer_iterator::value_type

    namespace std::ranges {
      template<class V, class Pattern>
      template<bool Const>
      struct split_view<V, Pattern>::outer_iterator<Const>::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;
        constexpr default_sentinel_t end() const;
      };
    }

#### Class template std::ranges::split_view::inner_iterator

    namespace std::ranges {
      template<class V, class 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 definition */;
        using value_type        = iter_value_t<iterator_t<Base>>;
        using difference_type   = iter_difference_t<iterator_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 (ForwardRange<V>) {
            auto tmp = *this;
            ++*this;
            return tmp;
          } else
            ++*this;
        }

        friend constexpr bool operator==(const inner_iterator& x, const inner_iterator& y)
          requires ForwardRange<Base>;
        friend constexpr bool operator!=(const inner_iterator& x, const inner_iterator& y)
          requires ForwardRange<Base>;

        friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t);
        friend constexpr bool operator==(default_sentinel_t, const inner_iterator& x);
        friend constexpr bool operator!=(const inner_iterator& x, default_sentinel_t y);
        friend constexpr bool operator!=(default_sentinel_t y, const inner_iterator& x);

        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 IndirectlySwappable<iterator_t<Base>>;
      };
    }

#### Class template std::ranges::common_view

    namespace std::ranges {
      template<View V>
        requires (!CommonRange<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<ViewableRange R>
          requires (!CommonRange<R> && Constructible<V, all_view<R>>)
        constexpr explicit common_view(R&& r);

        constexpr V base() const;

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

        constexpr auto begin() {
          if constexpr (RandomAccessRange<V> && SizedRange<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 (RandomAccessRange<const V> && SizedRange<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 (RandomAccessRange<V> && SizedRange<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 (RandomAccessRange<const V> && SizedRange<const V>)
            return ranges::begin(base_) + ranges::size(base_);
          else
            return
              common_iterator<iterator_t<const V>, sentinel_t<const V>>(ranges::end(base_));
        }
      };

      template<class R>
        common_view(R&&) -> common_view<all_view<R>>;
    }

#### Class template std::ranges::reverse_view

    namespace std::ranges {
      template<View V>
        requires BidirectionalRange<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);

        template<ViewableRange R>
          requires BidirectionalRange<R> && Constructible<V, all_view<R>>
        constexpr explicit reverse_view(R&& r);

        constexpr V base() const;

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

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

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

      template<class R>
        reverse_view(R&&) -> reverse_view<all_view<R>>;
    }

Retrieved from "https://en.cppreference.com/mwiki/index.php?title=cpp/header/ranges&oldid=110837"