26 Ranges library [ranges]

26.5 Range utilities [range.utility]

26.5.4 Sub-ranges [range.subrange]

26.5.4.1 General [range.subrange.general]

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

26.5.4.2 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)) is true.
Effects: Initializes begin_ with std​::​move(i) and end_ with s.
If StoreSize is true, initializes size_ with n.
[Note 1: 
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<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>);
Effects: Equivalent to:
  • If StoreSize is true, subrange(r, static_cast<decltype(size_)>(ranges​::​size(r))).
  • Otherwise, subrange(ranges​::​begin(r), ranges​::​end(r)).
template<different-from<subrange> PairLike> requires pair-like-convertible-from<PairLike, const I&, const S&> constexpr operator PairLike() const;
Effects: Equivalent to: return PairLike(begin_, end_);

26.5.4.3 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 constexpr (bidirectional_iterator<I>) { if (n < 0) { ranges::advance(begin_, n); if constexpr (StoreSize) size_ += to-unsigned-like(-n); return *this; } } auto d = n - ranges::advance(begin_, n, end_); if constexpr (StoreSize) size_ -= to-unsigned-like(d); return *this;
template<size_t N, class I, class S, subrange_kind K> requires ((N == 0 && copyable<I>) || N == 1) 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();