#
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 uses-nonqualification-pointer-conversion = / exposition only is_pointer_v<From> && is_pointer_v<To> && !convertible_to<remove_pointer_t<From>(*)[], remove_pointer_t<To>(*)[]>; template<class From, class To> concept convertible-to-non-slicing = / exposition only convertible_to<From, To> && !uses-nonqualification-pointer-conversion<decay_t<From>, decay_t<To>>; template<class T, class U, class V> concept pair-like-convertible-from = / exposition only !range<T> && !is_reference_v<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<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 / if StoreSize is true public: subrange() requires default_initializable<I> = 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<different-from<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<different-from<subrange> PairLike> requires pair-like-convertible-from<PairLike, const I&, const S&> constexpr operator PairLike() const; constexpr I begin() const requires copyable<I>; 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); constexpr subrange next(iter_difference_t<I> n = 1) const & requires forward_iterator<I>; constexpr subrange next(iter_difference_t<I> n = 1) &&; 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<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>; }

Follow Lee on X/Twitter - Father, Husband, Serial builder creating AI, crypto, games & web tools. We are friends :) AI Will Come To Life!

Check out: eBank.nz (Art Generator) | Netwrck.com (AI Tools) | Text-Generator.io (AI API) | BitBank.nz (Crypto AI) | ReadingTime (Kids Reading) | RewordGame | BigMultiplayerChess | WebFiddle | How.nz | Helix AI Assistant