622 KiB
[range.adaptors]
25 Ranges library [ranges]
25.7 Range adaptors [range.adaptors]
25.7.1 General [range.adaptors.general]
Subclause [range.adaptors] 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 1: vector 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]
25.7.2 Range adaptor objects [range.adaptor.object]
A range adaptor closure object is a unary function object that accepts a range argument.
For a range adaptor closure object C and an expression R such thatdecltype((R)) models range, the following expressions are equivalent:C(R) R | C
Given an additional range adaptor closure object D, the expression C | D produces another range adaptor closure object E.
E is a perfect forwarding call wrapper ([func.require]) with the following properties:
-
Its target object is an object d of type decay_t<decltype((D))> direct-non-list-initialized with D.
-
It has one bound argument entity, an object c of type decay_t<decltype((C))> direct-non-list-initialized with C.
-
Its call pattern is d(c(arg)), where arg is the argument used in a function call expression of E.
The expression C | D is well-formed if and only if the initializations of the state entities of E are all well-formed.
Given an object t of type T, where
t is a unary function object that accepts a range argument,
T models derived_from<range_adaptor_closure>,
T has no other base classes of type range_adaptor_closure for any other type U, and
T does not model range
then the implementation ensures that t is a range adaptor closure object.
The template parameter D for range_adaptor_closure may be an incomplete type.
If an expression of type cv D is used as an operand to the | operator,D shall be complete and model derived_from<range_adaptor_closure>.
The behavior of an expression involving an object of type cv D as an operand to the | operator is undefined if overload resolution selects a program-defined operator| function.
If an expression of type cv U is used as an operand to the | operator, where U has a base class of type range_adaptor_closure for some type T other than U, the behavior is undefined.
The behavior of a program that adds a specialization for range_adaptor_closure is undefined.
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 adaptor accepts more than one argument, then let range be an expression such that decltype((range)) models viewable_range, let args... be arguments such that adaptor(range, args...) is a well-formed expression as specified in the rest of subclause [range.adaptors], and let BoundArgs be a pack that denotes decay_t<decltype((args))>....
The expression adaptor(args...) produces a range adaptor closure object f that is a perfect forwarding call wrapper ([func.require]) with the following properties:
-
Its target object is a copy of adaptor.
-
Its bound argument entities bound_args consist of objects of types BoundArgs... direct-non-list-initialized with std::forward<decltype((args))>(args)..., respectively.
-
Its call pattern is adaptor(r, bound_args...), where r is the argument used in a function call expression of f.
The expression adaptor(args...) is well-formed if and only if the initialization of the bound argument entities of the result, as specified above, are all well-formed.
25.7.3 Movable wrapper [range.move.wrap]
Many types in this subclause are specified in terms of an exposition-only class template movable-box.
movable-box behaves exactly like optional with the following differences:
movable-box constrains its type parameter T withmove_constructible && is_object_v.
The default constructor of movable-box is equivalent to:constexpr movable-box() noexcept(is_nothrow_default_constructible_v)requires default_initializable: movable-box{in_place} {}
If copyable is not modeled, the copy assignment operator is equivalent to:constexpr movable-box& operator=(const movable-box& that)noexcept(is_nothrow_copy_constructible_v)requires copy_constructible {if (this != addressof(that)) {if (that) emplace(*that); else reset(); }return *this;}
If movable is not modeled, the move assignment operator is equivalent to:constexpr movable-box& operator=(movable-box&& that)noexcept(is_nothrow_move_constructible_v) {if (this != addressof(that)) {if (that) emplace(std::move(*that)); else reset(); }return *this;}
Recommended practice:
-
If copy_constructible is true,movable-box should store only a T if either T models copyable, oris_nothrow_move_constructible_v && is_nothrow_copy_constructible_v is true.
-
Otherwise, movable-box should store only a T if either T models movable oris_nothrow_move_constructible_v is true.
25.7.4 Non-propagating cache [range.nonprop.cache]
Some types in [range.adaptors] are specified in terms of an exposition-only class template non-propagating-cache.
non-propagating-cache behaves exactly like optional with the following differences:
non-propagating-cache constrains its type parameter T with is_object_v.
The copy constructor is equivalent to:constexpr non-propagating-cache(const non-propagating-cache&) noexcept {}
The move constructor is equivalent to:constexpr non-propagating-cache(non-propagating-cache&& other) noexcept { other.reset();}
The copy assignment operator is equivalent to:constexpr non-propagating-cache& operator=(const non-propagating-cache& other) noexcept {if (addressof(other) != this) reset(); return *this;}
The move assignment operator is equivalent to:constexpr non-propagating-cache& operator=(non-propagating-cache&& other) noexcept { reset(); other.reset(); return *this;}
non-propagating-cache has an additional member function template
specified as follows:
ð
template<class I> constexpr T& emplace-deref(const I& i); // exposition only
Mandates: The declaration T t(*i); is well-formed
for some invented variable t.
[Note 1:
If *i is a prvalue of type cv T,
there is no requirement that it is movable ([dcl.init.general]).
â end note]
Effects: Calls reset().
Then direct-non-list-initializes the contained value with *i.
Postconditions: *this contains a value.
Returns: A reference to the new contained value.
Throws: Any exception thrown by the initialization of the contained value.
Remarks: If an exception is thrown during the initialization of T,*this does not contain a value, and
the previous value (if any) has been destroyed.
[Note 2:
non-propagating-cache enables an input view to temporarily cache values as it is iterated over.
â end note]
25.7.5 Range adaptor helpers [range.adaptor.helpers]
namespace std::ranges {template<class F, class Tuple>constexpr auto tuple-transform(F&& f, Tuple&& t) { // exposition onlyreturn apply([&]<class... Ts>(Ts&&... elements) {return tuple<invoke_result_t<F&, Ts>...>(invoke(f, std::forward(elements))...); }, std::forward(t)); }template<class F, class Tuple>constexpr void tuple-for-each(F&& f, Tuple&& t) { // exposition only apply([&]<class... Ts>(Ts&&... elements) {(static_cast(invoke(f, std::forward(elements))), ...); }, std::forward(t)); }templateconstexpr T& as-lvalue(T&& t) { // exposition onlyreturn static_cast<T&>(t); }template<bool Const, class... Views>concept all-random-access = // exposition only(random_access_range<maybe-const<Const, Views>> && ...); template<bool Const, class... Views>concept all-bidirectional = // exposition only(bidirectional_range<maybe-const<Const, Views>> && ...); template<bool Const, class... Views>concept all-forward = // exposition only(forward_range<maybe-const<Const, Views>> && ...);}
25.7.6 All view [range.all]
25.7.6.1 General [range.all.general]
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 expressionviews::all(E) is expression-equivalent to:
25.7.6.2 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_vclass ref_view : public view_interface<ref_view> {private: R* r_; // exposition onlypublic:template<different-from<ref_view> T>requires see belowconstexpr ref_view(T&& t); constexpr R& base() const { return **r_; }constexpr iterator_t begin() const { return ranges::begin(**r_); }constexpr sentinel_t end() const { return ranges::end(**r_); }constexpr bool empty() constrequires requires { ranges::empty(**r_); }{ return ranges::empty(**r_); }constexpr auto size() const requires sized_range{ return ranges::size(**r_); }constexpr auto reserve_hint() const requires approximately_sized_range{ return ranges::reserve_hint(**r_); }constexpr auto data() const requires contiguous_range{ return ranges::data(**r_); }}; template ref_view(R&) -> ref_view;}
template<[different-from](range.utility.helpers#concept:different-from "25.5.2 Helper concepts [range.utility.helpers]")<ref_view> T> requires see below constexpr ref_view(T&& t);
Effects: Initializes r_ withaddressof(static_cast<R&>(std::forward(t))).
Remarks: Let FUN denote the exposition-only functionsvoid FUN(R&);void FUN(R&&) = delete;
The expression in the requires-clause is equivalent to:convertible_to<T, R&> && requires { FUN(declval()); }
25.7.6.3 Class template owning_view [range.owning.view]
owning_view is a move-only view of the elements of some other range.
namespace std::ranges {template<range R>requires movable && (!is-initializer-list) // see [range.refinements]class owning_view : public view_interface<owning_view> {private: R r_ = R(); // exposition onlypublic: owning_view() requires default_initializable = default; constexpr owning_view(R&& t);
owning_view(owning_view&&) = default; owning_view& operator=(owning_view&&) = default; constexpr R& base() & noexcept { return r_; }constexpr const R& base() const & noexcept { return r_; }constexpr R&& base() && noexcept { return std::move(r_); }constexpr const R&& base() const && noexcept { return std::move(r_); }constexpr iterator_t begin() { return ranges::begin(r_); }constexpr sentinel_t end() { return ranges::end(r_); }constexpr auto begin() const requires range{ return ranges::begin(r_); }constexpr auto end() const requires range{ return ranges::end(r_); }constexpr bool empty() requires requires { ranges::empty(r_); }{ return ranges::empty(r_); }constexpr bool empty() const requires requires { ranges::empty(r_); }{ return ranges::empty(r_); }constexpr auto size() requires sized_range{ return ranges::size(r_); }constexpr auto size() const requires sized_range{ return ranges::size(r_); }constexpr auto reserve_hint() requires approximately_sized_range{ return ranges::reserve_hint(r_); }constexpr auto reserve_hint() const requires approximately_sized_range{ return ranges::reserve_hint(r_); }constexpr auto data() requires contiguous_range{ return ranges::data(r_); }constexpr auto data() const requires contiguous_range{ return ranges::data(r_); }};}
constexpr owning_view(R&& t);
Effects: Initializes r_ with std::move(t).
25.7.7 As rvalue view [range.as.rvalue]
25.7.7.1 Overview [range.as.rvalue.overview]
as_rvalue_view presents a view of an underlying sequence with the same behavior as the underlying sequence except that its elements are rvalues.
Some generic algorithms can be called with an as_rvalue_view to replace copying with moving.
The name views::as_rvalue denotes a range adaptor object ([range.adaptor.object]).
Let E be an expression and let T be decltype((E)).
The expression views::as_rvalue(E) is expression-equivalent to:
-
views::all(E) ifT models input_range andsame_as<range_rvalue_reference_t, range_reference_t> is true.
-
Otherwise, as_rvalue_view(E).
[Example 1: vector words = {"the", "quick", "brown", "fox", "ate", "a", "pterodactyl"}; vector new_words; ranges::copy(words | views::as_rvalue, back_inserter(new_words)); // moves each string from words into new_words â end example]
25.7.7.2 Class template as_rvalue_view [range.as.rvalue.view]
namespace std::ranges {template<view V>requires input_rangeclass as_rvalue_view : public view_interface<as_rvalue_view> { V base_ = V(); // exposition onlypublic: as_rvalue_view() requires default_initializable = default; constexpr explicit as_rvalue_view(V base); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr auto begin() requires (){ return move_iterator(ranges::begin(base_)); }constexpr auto begin() const requires range{ return move_iterator(ranges::begin(base_)); }constexpr auto end() requires (
) {if constexpr (common_range) {return move_iterator(ranges::end(base_)); } else {return move_sentinel(ranges::end(base_)); }}constexpr auto end() const requires range {if constexpr (common_range) {return move_iterator(ranges::end(base_)); } else {return move_sentinel(ranges::end(base_)); }}constexpr auto size() requires sized_range { return ranges::size(base_); }constexpr auto size() const requires sized_range { return ranges::size(base_); }constexpr auto reserve_hint() requires approximately_sized_range{ return ranges::reserve_hint(base_); }constexpr auto reserve_hint() const requires approximately_sized_range{ return ranges::reserve_hint(base_); }}; template as_rvalue_view(R&&) -> as_rvalue_view<views::all_t>;}
constexpr explicit as_rvalue_view(V base);
Effects: Initializes base_ with std::move(base).
25.7.8 Filter view [range.filter]
25.7.8.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 tofilter_view(E, P).
[Example 1: vector is{ 0, 1, 2, 3, 4, 5, 6 };auto evens = views::filter(is, [](int i) { return 0 == i % 2; });for (int i : evens) cout << i << ' '; // prints 0 2 4 6 â end example]
25.7.8.2 Class template filter_view [range.filter.view]
namespace std::ranges {template<input_range V, indirect_unary_predicate<iterator_t> Pred>requires view && is_object_vclass filter_view : public view_interface<filter_view<V, Pred>> {private: V base_ = V(); // exposition only**movable-box pred_; // exposition only// [range.filter.iterator], class filter_view::iteratorclass iterator; // exposition only// [range.filter.sentinel], class filter_view::sentinelclass sentinel; // exposition onlypublic: filter_view() requires default_initializable && default_initializable = default; constexpr explicit filter_view(V base, Pred pred); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr const Pred& pred() const; constexpr iterator begin(); constexpr auto end() {if constexpr (common_range)return iterator{*this, ranges::end(base_)}; elsereturn sentinel{*this}; }}; template<class R, class Pred> filter_view(R&&, Pred) -> filter_view<views::all_t, Pred>;}
constexpr explicit filter_view(V base, Pred pred);
Effects: Initializes base_ with std::move(base) and initializespred_ with std::move(pred).
constexpr const Pred& pred() const;
Effects: Equivalent to: return **pred_*;
constexpr iterator begin();
Preconditions: pred_.has_value() is true.
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 thefilter_view for use on subsequent calls.
25.7.8.3 Class filter_view::iterator [range.filter.iterator]
namespace std::ranges {template<input_range V, indirect_unary_predicate<iterator_t> Pred>requires view && is_object_vclass filter_view<V, Pred>::iterator {private: iterator_t current_ = iterator_t(); // exposition only filter_view* parent_ = nullptr; // exposition onlypublic:using iterator_concept = see below; using iterator_category = see below; // not always presentusing value_type = range_value_t; using difference_type = range_difference_t; iterator() requires default_initializable<iterator_t> = default; constexpr iterator(filter_view& parent, iterator_t current); constexpr const iterator_t& base() const & noexcept; constexpr iterator_t base() &&; constexpr range_reference_t operator*() const; constexpr iterator_t operator->() constrequires has-arrow<iterator_t> && copyable<iterator_t>; constexpr iterator& operator++(); constexpr void operator++(int); constexpr iterator operator++(int) requires forward_range; constexpr iterator& operator--() requires bidirectional_range; constexpr iterator operator--(int) requires bidirectional_range; friend constexpr bool operator==(const iterator& x, const iterator& y)requires equality_comparable<iterator_t>; friend constexpr range_rvalue_reference_t 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>; };}
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, theniterator_concept denotes bidirectional_iterator_tag.
-
Otherwise, if V models forward_range, theniterator_concept denotes forward_iterator_tag.
-
Otherwise, iterator_concept denotes input_iterator_tag.
The member typedef-name iterator_category is defined if and only if V models forward_range.
In that case,iterator::iterator_category is defined as follows:
-
Let C denote the typeiterator_traits<iterator_t>::iterator_category.
-
If C modelsderived_from<bidirectional_iterator_tag>, then iterator_category denotes bidirectional_iterator_tag.
-
Otherwise, if C modelsderived_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) andparent_ with addressof(parent).
constexpr const iterator_t<V>& base() const & noexcept;
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](range.utility.helpers#concept:has-arrow "25.5.2 Helper concepts [range.utility.helpers]")<iterator_t<V>> && [copyable](concepts.object#concept:copyable "18.6 Object concepts [concepts.object]")<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](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<V>;
Effects: Equivalent to:auto tmp = *this;++*this;return tmp;
constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<V>;
Effects: Equivalent to:do--current_;while (!invoke(**parent_->pred_, **current_));return *this;
constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<V>;
Effects: Equivalent to:auto tmp = *this;--*this;return tmp;
friend constexpr bool operator==(const iterator& x, const iterator& y) requires [equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_comparable [concept.equalitycomparable]")<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](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept indirectly_swappable [alg.req.ind.swap]")<iterator_t<V>>;
Effects: Equivalent to ranges::iter_swap(x.current_, y.current_).
25.7.8.4 Class filter_view::sentinel [range.filter.sentinel]
namespace std::ranges {template<input_range V, indirect_unary_predicate<iterator_t> Pred>requires view && is_object_vclass filter_view<V, Pred>::sentinel {private: sentinel_t end_ = sentinel_t(); // exposition onlypublic:sentinel() = default; constexpr explicit sentinel(filter_view& parent); constexpr sentinel_t 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_;
25.7.9 Transform view [range.transform]
25.7.9.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 expressionviews::transform(E, F) is expression-equivalent totransform_view(E, F).
[Example 1: vector is{ 0, 1, 2, 3, 4 };auto squares = views::transform(is, [](int i) { return i * i; });for (int i : squares) cout << i << ' '; // prints 0 1 4 9 16 â end example]
25.7.9.2 Class template transform_view [range.transform.view]
namespace std::ranges {template<input_range V, move_constructible F>requires view && is_object_v &®ular_invocable<F&, range_reference_t> &&can-reference<invoke_result_t<F&, range_reference_t>>class transform_view : public view_interface<transform_view<V, F>> {private:// [range.transform.iterator], class template transform_view::iteratortemplate struct iterator; // exposition only// [range.transform.sentinel], class template transform_view::sentineltemplate struct sentinel; // exposition only V base_ = V(); // exposition only**movable-box fun_; // exposition onlypublic: transform_view() requires default_initializable && default_initializable = default; constexpr explicit transform_view(V base, F fun); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr iterator begin(); constexpr iterator begin() constrequires range &®ular_invocable<const F&, range_reference_t>; constexpr sentinel end(); constexpr iterator end() requires common_range; constexpr sentinel end() constrequires range &®ular_invocable<const F&, range_reference_t>; constexpr iterator end() constrequires common_range &®ular_invocable<const F&, range_reference_t>; constexpr auto size() requires sized_range { return ranges::size(base_); }constexpr auto size() const requires sized_range{ return ranges::size(base_); }constexpr auto reserve_hint() requires approximately_sized_range{ return ranges::reserve_hint(base_); }constexpr auto reserve_hint() const requires approximately_sized_range{ return ranges::reserve_hint(base_); }}; template<class R, class F> transform_view(R&&, F) -> transform_view<views::all_t, F>;}
constexpr explicit transform_view(V base, F fun);
Effects: Initializes base_ with std::move(base) andfun_ with std::move(fun).
constexpr iterator<false> begin();
Effects: Equivalent to:return iterator{*this, ranges::begin(base_)};
constexpr iterator<true> begin() const requires [range](range.range#concept:range "25.4.2 Ranges [range.range]")<const V> && [regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3 Concept regular_invocable [concept.regularinvocable]")<const F&, range_reference_t<const V>>;
Effects: Equivalent to:return iterator{*this, ranges::begin(base_)};
constexpr sentinel<false> end();
Effects: Equivalent to:return sentinel{ranges::end(base_)};
constexpr iterator<false> end() requires [common_range](range.refinements#concept:common_range "25.4.6 Other range refinements [range.refinements]")<V>;
Effects: Equivalent to:return iterator{*this, ranges::end(base_)};
constexpr sentinel<true> end() const requires [range](range.range#concept:range "25.4.2 Ranges [range.range]")<const V> && [regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3 Concept regular_invocable [concept.regularinvocable]")<const F&, range_reference_t<const V>>;
Effects: Equivalent to:return sentinel{ranges::end(base_)};
constexpr iterator<true> end() const requires [common_range](range.refinements#concept:common_range "25.4.6 Other range refinements [range.refinements]")<const V> && [regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3 Concept regular_invocable [concept.regularinvocable]")<const F&, range_reference_t<const V>>;
Effects: Equivalent to:return iterator{*this, ranges::end(base_)};
25.7.9.3 Class template transform_view::iterator [range.transform.iterator]
namespace std::ranges {template<input_range V, move_constructible F>requires view && is_object_v &®ular_invocable<F&, range_reference_t> &&can-reference<invoke_result_t<F&, range_reference_t>>templateclass transform_view<V, F>::iterator {private:using Parent = maybe-const<Const, transform_view>; // exposition onlyusing Base = maybe-const<Const, V>; // exposition only iterator_t<Base> current_ = iterator_t<Base>(); // exposition onlyParent parent_ = nullptr; // exposition onlypublic:using iterator_concept = see below; using iterator_category = see below; // not always presentusing value_type = remove_cvref_t<invoke_result_t<maybe-const<Const, F>&, range_reference_t<Base>>>; using difference_type = range_difference_t<Base>; iterator() requires default_initializable<iterator_t<Base>> = default; constexpr iterator(Parent& parent, iterator_t<Base> current); constexpr iterator(iterator i)requires Const && convertible_to<iterator_t, iterator_t<Base>>; constexpr const iterator_t<Base>& base() const & noexcept; constexpr iterator_t<Base> base() &&; constexpr decltype(auto) operator() constnoexcept(noexcept(invoke(**parent_->fun_, **current_))) {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) constrequires 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 sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>; };}
iterator::iterator_concept is defined as follows:
-
If Base models random_access_range, theniterator_concept denotes random_access_iterator_tag.
-
Otherwise, if Base models bidirectional_range, theniterator_concept denotes bidirectional_iterator_tag.
-
Otherwise, if Base models forward_range, theniterator_concept denotes forward_iterator_tag.
-
Otherwise, iterator_concept denotes input_iterator_tag.
The member typedef-name iterator_category is defined if and only if Base models forward_range.
In that case,iterator::iterator_category is defined as follows: Let C denote the typeiterator_traits<iterator_t<Base>>::iterator_category.
-
If is_reference_v<invoke_result_t<maybe-const<Const, 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.
constexpr iterator(Parent& parent, iterator_t<Base> current);
Effects: Initializes current_ with std::move(current) andparent_ with addressof(parent).
constexpr iterator(iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<V>, iterator_t<Base>>;
Effects: Initializes current_ with std::move(i.current_) andparent_ with i.parent_.
constexpr const iterator_t<Base>& base() const & noexcept;
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](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto tmp = *this;++*this;return tmp;
constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:--current_;return *this;
constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto tmp = *this;--*this;return tmp;
constexpr iterator& operator+=(difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:current_ += n;return *this;
constexpr iterator& operator-=(difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:current_ -= n;return *this;
friend constexpr bool operator==(const iterator& x, const iterator& y) requires [equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_comparable [concept.equalitycomparable]")<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](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return x.current_ < y.current_;
friend constexpr bool operator>(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return y < x;
friend constexpr bool operator<=(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return !(y < x);
friend constexpr bool operator>=(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return !(x < y);
friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base> && [three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4 Concept three_way_comparable [cmp.concept]")<iterator_t<Base>>;
Effects: Equivalent to: return x.current_ <=> y.current_;
friend constexpr iterator operator+(iterator i, difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>; friend constexpr iterator operator+(difference_type n, iterator i) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return iterator{*i.parent_, i.current_ + n};
friend constexpr iterator operator-(iterator i, difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return iterator{*i.parent_, i.current_ - n};
friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<iterator_t<Base>, iterator_t<Base>>;
Effects: Equivalent to: return x.current_ - y.current_;
25.7.9.4 Class template transform_view::sentinel [range.transform.sentinel]
namespace std::ranges {template<input_range V, move_constructible F>requires view && is_object_v &®ular_invocable<F&, range_reference_t> &&can-reference<invoke_result_t<F&, range_reference_t>>templateclass transform_view<V, F>::sentinel {private:using Parent = maybe-const<Const, transform_view>; // exposition onlyusing Base = maybe-const<Const, V>; // exposition only sentinel_t<Base> end_ = sentinel_t<Base>(); // exposition onlypublic:sentinel() = default; constexpr explicit sentinel(sentinel_t<Base> end); constexpr sentinel(sentinel i)requires Const && convertible_to<sentinel_t, sentinel_t<Base>>; constexpr sentinel_t<Base> base() const; templaterequires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>friend constexpr bool operator==(const iterator& x, const sentinel& y); templaterequires sized_sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>friend constexpr range_difference_t<maybe-const<OtherConst, V>>operator-(const iterator& x, const sentinel& y); templaterequires sized_sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>friend constexpr range_difference_t<maybe-const<OtherConst, V>>operator-(const sentinel& y, const iterator& x); };}
constexpr explicit sentinel(sentinel_t<Base> end);
Effects: Initializes end_ with end.
constexpr sentinel(sentinel<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<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_;
template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7 Concept sentinel_for [iterator.concept.sentinel]")<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
Effects: Equivalent to: return x.current_ == y.end_;
template<bool OtherConst> requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr range_difference_t<maybe-const<OtherConst, V>> operator-(const iterator<OtherConst>& x, const sentinel& y);
Effects: Equivalent to: return x.current_ - y.end_;
template<bool OtherConst> requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr range_difference_t<maybe-const<OtherConst, V>> operator-(const sentinel& y, const iterator<OtherConst>& x);
Effects: Equivalent to: return y.end_ - x.current_;
25.7.10 Take view [range.take]
25.7.10.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 modelconvertible_to,views::take(E, F) is ill-formed.
Otherwise, the expression views::take(E, F) is expression-equivalent to:
-
If T is a specialization of empty_view ([range.empty.view]), then ((void)F, decay-copy(E)), except that the evaluations of E and F are indeterminately sequenced.
-
Otherwise, if T modelsrandom_access_range and sized_range and is a specialization ofspan ([views.span]),basic_string_view ([string.view]), orsubrange ([range.subrange]), thenU(ranges::begin(E), ranges::begin(E) + std::min(ranges::distance(E), F)), except that E is evaluated only once, where U is a type determined as follows:
if T is a specialization of span, then U is span<typename T::element_type>;
otherwise, if T is a specialization of basic_string_view, then U is T;
otherwise, T is a specialization of subrange, andU is subrange<iterator_t>;
-
otherwise, if T is a specialization of iota_view ([range.iota.view]) that models random_access_range and sized_range, theniota_view(ranges::begin(E),(ranges::begin(E) + std::min(ranges::distance(E), F))), except that E is evaluated only once.
-
Otherwise, if T is a specialization of repeat_view ([range.repeat.view]):
if T models sized_range, thenviews::repeat(*E.value_, std::min(ranges::distance(E), F)) except that E is evaluated only once;
otherwise, views::repeat(*E.value_, static_cast(F)).
[Example 1: vector is{0,1,2,3,4,5,6,7,8,9};for (int i : is | views::take(5)) cout << i << ' '; // prints 0 1 2 3 4 â end example]
25.7.10.2 Class template take_view [range.take.view]
namespace std::ranges {template<view V>class take_view : public view_interface<take_view> {private: V base_ = V(); // exposition only range_difference_t count_ = 0; // exposition only// [range.take.sentinel], class template take_view::sentineltemplate class sentinel; // exposition onlypublic: take_view() requires default_initializable = default; constexpr explicit take_view(V base, range_difference_t count); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr auto begin() requires () {if constexpr (sized_range) {if constexpr (random_access_range) {return ranges::begin(base_); } else {auto sz = range_difference_t(size()); return counted_iterator(ranges::begin(base_), sz); }} else if constexpr (sized_sentinel_for<sentinel_t, iterator_t>) {auto it = ranges::begin(base_); auto sz = std::min(count_, ranges::end(base_) - it); return counted_iterator(std::move(it), sz); } else {return counted_iterator(ranges::begin(base_), count_); }}constexpr auto begin() const requires range {if constexpr (sized_range) {if constexpr (random_access_range) {return ranges::begin(base_); } else {auto sz = range_difference_t(size()); return counted_iterator(ranges::begin(base_), sz); }} else if constexpr (sized_sentinel_for<sentinel_t, iterator_t>) {auto it = ranges::begin(base_); auto sz = std::min(count_, ranges::end(base_) - it); return counted_iterator(std::move(it), sz); } else {return counted_iterator(ranges::begin(base_), count_); }}constexpr auto end() requires (
) {if constexpr (sized_range) {if constexpr (random_access_range)return ranges::begin(base_) + range_difference_t(size()); elsereturn default_sentinel; } else if constexpr (sized_sentinel_for<sentinel_t, iterator_t>) {return default_sentinel; } else {return sentinel{ranges::end(base_)}; }}constexpr auto end() const requires range {if constexpr (sized_range) {if constexpr (random_access_range)return ranges::begin(base_) + range_difference_t(size()); elsereturn default_sentinel; } else if constexpr (sized_sentinel_for<sentinel_t, iterator_t>) {return default_sentinel; } else {return sentinel{ranges::end(base_)}; }}constexpr auto size() requires sized_range {auto n = ranges::size(base_); return ranges::min(n, static_cast<decltype(n)>(count_)); }constexpr auto size() const requires sized_range {auto n = ranges::size(base_); return ranges::min(n, static_cast<decltype(n)>(count_)); }constexpr auto reserve_hint() {if constexpr (approximately_sized_range) {auto n = static_cast<range_difference_t>(ranges::reserve_hint(base_)); return to-unsigned-like(ranges::min(n, count_)); }return to-unsigned-like(count_); }constexpr auto reserve_hint() const {if constexpr (approximately_sized_range) {auto n = static_cast<range_difference_t>(ranges::reserve_hint(base_)); return to-unsigned-like(ranges::min(n, count_)); }return to-unsigned-like(count_); }}; template take_view(R&&, range_difference_t)-> take_view<views::all_t>;}
constexpr explicit take_view(V base, range_difference_t<V> count);
Preconditions: count >= 0 is true.
Effects: Initializes base_ with std::move(base) andcount_ with count.
25.7.10.3 Class template take_view::sentinel [range.take.sentinel]
namespace std::ranges {template<view V>templateclass take_view::sentinel {private:using Base = maybe-const<Const, V>; // exposition onlytemplateusing CI = counted_iterator<iterator_t<maybe-const<OtherConst, V>>>; // exposition only sentinel_t<Base> end_ = sentinel_t<Base>(); // exposition onlypublic:sentinel() = default; constexpr explicit sentinel(sentinel_t<Base> end); constexpr sentinel(sentinel s)requires Const && convertible_to<sentinel_t, sentinel_t<Base>>; constexpr sentinel_t<Base> base() const; friend constexpr bool operator==(const CI& y, const sentinel& x); templaterequires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>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](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<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);
template requires sentinel_for<sentinel_t, iterator_t<maybe-const<OtherConst, V>>> friend constexpr bool operator==(const CI& y, const sentinel& x); `
Effects: Equivalent to:return y.count() == 0 || y.base() == x.end_;
25.7.11 Take while view [range.take.while]
25.7.11.1 Overview [range.take.while.overview]
Given a unary predicate pred and a view r,take_while_view produces a view of the range [ranges::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 1: 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 = views::istream(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]
25.7.11.2 Class template take_while_view [range.take.while.view]
namespace std::ranges {template<view V, class Pred>requires input_range && is_object_v &&indirect_unary_predicate<const Pred, iterator_t>class take_while_view : public view_interface<take_while_view<V, Pred>> {// [range.take.while.sentinel], class template take_while_view::sentineltemplate class sentinel; // exposition only V base_ = V(); // exposition only**movable-box pred_; // exposition onlypublic: take_while_view() requires default_initializable && default_initializable = default; constexpr explicit take_while_view(V base, Pred pred); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr const Pred& pred() const; constexpr auto begin() requires (){ return ranges::begin(base_); }constexpr auto begin() constrequires range &&indirect_unary_predicate<const Pred, iterator_t>{ return ranges::begin(base_); }constexpr auto end() requires (
){ return sentinel(ranges::end(base_), addressof(**pred_)); }constexpr auto end() constrequires range &&indirect_unary_predicate<const Pred, iterator_t>{ return sentinel(ranges::end(base_), addressof(**pred_)); }}; template<class R, class Pred> take_while_view(R&&, Pred) -> take_while_view<views::all_t, Pred>;}
constexpr explicit take_while_view(V base, Pred pred);
Effects: Initializes base_ with std::move(base) andpred_ with std::move(pred).
constexpr const Pred& pred() const;
Effects: Equivalent to: return **pred_*;
25.7.11.3 Class template take_while_view::sentinel [range.take.while.sentinel]
namespace std::ranges {template<view V, class Pred>requires input_range && is_object_v &&indirect_unary_predicate<const Pred, iterator_t>templateclass take_while_view<V, Pred>::sentinel {using Base = maybe-const<Const, V>; // exposition only sentinel_t<Base> end_ = sentinel_t<Base>(); // exposition onlyconst Pred* pred_ = nullptr; // exposition onlypublic:sentinel() = default; constexpr explicit sentinel(sentinel_t<Base> end, const Pred* pred); constexpr sentinel(sentinel s)requires Const && convertible_to<sentinel_t, sentinel_t<Base>>; constexpr sentinel_t<Base> base() const { return end_; }friend constexpr bool operator==(const iterator_t<Base>& x, const sentinel& y); templaterequires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>friend constexpr bool operator==(const iterator_t<maybe-const<OtherConst, V>>& 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](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;
Effects: Initializes end_ with std::move(s.end_) andpred_ with s.pred_.
`friend constexpr bool operator==(const iterator_t& x, const sentinel& y);
template requires sentinel_for<sentinel_t, iterator_t<maybe-const<OtherConst, V>>> friend constexpr bool operator==(const iterator_t<maybe-const<OtherConst, V>>& x, const sentinel& y); `
Effects: Equivalent to:return y.end_ == x || !invoke(*y.pred_, *x);
25.7.12 Drop view [range.drop]
25.7.12.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 modelconvertible_to,views::drop(E, F) is ill-formed.
Otherwise, the expression views::drop(E, F) is expression-equivalent to:
-
If T is a specialization ofempty_view ([range.empty.view]), then ((void)F, decay-copy(E)), except that the evaluations of E and F are indeterminately sequenced.
-
Otherwise, if T modelsrandom_access_range and sized_range and is
a specialization of span ([views.span]),
a specialization of basic_string_view ([string.view]),
a specialization of iota_view ([range.iota.view]), or
a specialization of subrange ([range.subrange]) where T::StoreSize is false,
then U(ranges::begin(E) + std::min(ranges::distance(E), F), ranges::end(E)), except that E is evaluated only once, where U is span<typename T::element_type> if T is a specialization of span and T otherwise.
-
Otherwise, if T is a specialization of subrange that models random_access_range and sized_range, thenT(ranges::begin(E) + std::min(ranges::distance(E), F), ranges::end(E),to-unsigned-like(ranges::distance(E) - std::min(ranges::distance(E), F))), except that E and F are each evaluated only once.
-
Otherwise, if T is a specialization of repeat_view ([range.repeat.view]):
if T models sized_range, thenviews::repeat(*E.value_, ranges::distance(E) - std::min(ranges::distance(E), F)) except that E is evaluated only once;
otherwise, ((void)F, decay-copy(E)), except that the evaluations of E and F are indeterminately sequenced.
[Example 1: auto ints = views::iota(0) | views::take(10);for (auto i : ints | views::drop(5)) { cout << i << ' '; // prints 5 6 7 8 9} â end example]
25.7.12.2 Class template drop_view [range.drop.view]
namespace std::ranges {template<view V>class drop_view : public view_interface<drop_view> {public: drop_view() requires default_initializable = default; constexpr explicit drop_view(V base, range_difference_t count); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr auto begin()requires (!(simple-view &&random_access_range && sized_range)); constexpr auto begin() constrequires random_access_range && sized_range; constexpr auto end() requires (){ return ranges::end(base_); }constexpr auto end() const requires range{ return ranges::end(base_); }constexpr auto size() requires sized_range {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 auto s = ranges::size(base_); const auto c = static_cast<decltype(s)>(count_); return s < c ? 0 : s - c; }constexpr auto reserve_hint() requires approximately_sized_range {const auto s = static_cast<range_difference_t>(ranges::reserve_hint(base_)); return to-unsigned-like(s < count_ ? 0 : s - count_); }constexpr auto reserve_hint() const requires approximately_sized_range {const auto s = static_cast<range_difference_t>(ranges::reserve_hint(base_)); return to-unsigned-like(s < count_ ? 0 : s - count_); }private: V base_ = V(); // exposition only range_difference_t count_ = 0; // exposition only}; template drop_view(R&&, range_difference_t) -> drop_view<views::all_t>;}
constexpr explicit drop_view(V base, range_difference_t<V> count);
Preconditions: count >= 0 is true.
Effects: Initializes base_ with std::move(base) andcount_ with count.
constexpr auto begin() requires (!([simple-view](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]")<V> && [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<const V> && [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<const V>)); constexpr auto begin() const requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<const V> && [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<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 1:
Without this, applying a reverse_view over a drop_view would have quadratic iteration complexity.
â end note]
25.7.13 Drop while view [range.drop.while]
25.7.13.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 1: constexpr auto source = " \t \t \t hello there"sv;auto is_invisible = [](const auto x) { return x == ' ' || x == '\t'; };auto skip_ws = views::drop_while(source, is_invisible);for (auto c : skip_ws) { cout << c; // prints hello there with no leading space} â end example]
25.7.13.2 Class template drop_while_view [range.drop.while.view]
namespace std::ranges {template<view V, class Pred>requires input_range && is_object_v &&indirect_unary_predicate<const Pred, iterator_t>class drop_while_view : public view_interface<drop_while_view<V, Pred>> {public: drop_while_view() requires default_initializable && default_initializable = default; constexpr explicit drop_while_view(V base, Pred pred); constexpr V base() const & requires copy_constructible { 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**movable-box pred_; // exposition only}; template<class R, class Pred> drop_while_view(R&&, Pred) -> drop_while_view<views::all_t, Pred>;}
constexpr explicit drop_while_view(V base, Pred pred);
Effects: Initializes base_ with std::move(base) andpred_ with std::move(pred).
constexpr const Pred& pred() const;
Effects: Equivalent to: return **pred_*;
constexpr auto begin();
Preconditions: pred_.has_value() is true.
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 1:
Without this, applying a reverse_view over a drop_while_view would have quadratic iteration complexity.
â end note]
25.7.14 Join view [range.join]
25.7.14.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 expressionviews::join(E) is expression-equivalent tojoin_view<views::all_t<decltype((E))>>{E}.
[Example 1: vector ss{"hello", " ", "world", "!"};for (char ch : ss | views::join) cout << ch; // prints hello world! â end example]
25.7.14.2 Class template join_view [range.join.view]
namespace std::ranges {template<input_range V>requires view && input_range<range_reference_t>class join_view : public view_interface<join_view> {private:using InnerRng = range_reference_t; // exposition only// [range.join.iterator], class template join_view::iteratortemplatestruct iterator; // exposition only// [range.join.sentinel], class template join_view::sentineltemplatestruct sentinel; // exposition only V base_ = V(); // exposition only**non-propagating-cache<iterator_t> outer_; // exposition only, present only// when non-propagating-cache<remove_cv_t<InnerRng>> inner_; // exposition only, present only// if is_reference_v<InnerRng> is falsepublic: join_view() requires default_initializable = default; constexpr explicit join_view(V base); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr auto begin() {if constexpr (forward_range) {constexpr bool use_const = simple-view && is_reference_v<InnerRng>; return iterator<use_const>{*this, ranges::begin(base_)}; } else {outer_ = ranges::begin(base_); return iterator{*this}; }}constexpr auto begin() constrequires forward_range && is_reference_v<range_reference_t> &&input_range<range_reference_t>{ return iterator{*this, ranges::begin(base_)}; }constexpr auto end() {if constexpr (forward_range && is_reference_v<InnerRng> && forward_range<InnerRng> &&common_range && common_range<InnerRng>)return iterator<simple-view>{*this, ranges::end(base_)}; elsereturn sentinel<simple-view>{*this}; }constexpr auto end() constrequires forward_range && is_reference_v<range_reference_t> &&input_range<range_reference_t> {if constexpr (forward_range<range_reference_t> &&common_range &&common_range<range_reference_t>)return iterator{*this, ranges::end(base_)}; elsereturn sentinel{*this}; }}; templateexplicit join_view(R&&) -> join_view<views::all_t>;}
constexpr explicit join_view(V base);
Effects: Initializes base_ with std::move(base).
25.7.14.3 Class template join_view::iterator [range.join.iterator]
namespace std::ranges {template<input_range V>requires view && input_range<range_reference_t>templatestruct join_view::iterator {private:using Parent = maybe-const<Const, join_view>; // exposition onlyusing Base = maybe-const<Const, V>; // exposition onlyusing OuterIter = iterator_t<Base>; // exposition onlyusing InnerIter = iterator_t<range_reference_t<Base>>; // exposition onlystatic constexpr bool ref-is-glvalue = // exposition only is_reference_v<range_reference_t<Base>>; OuterIter outer_ = OuterIter(); // exposition only, present only// if Base models forward_range optional<InnerIter> inner_; // exposition onlyParent parent_ = nullptr; // exposition onlyconstexpr void satisfy(); // exposition onlyconstexpr OuterIter& outer(); // exposition onlyconstexpr const OuterIter& outer() const; // exposition onlyconstexpr iterator(Parent& parent, OuterIter outer)requires forward_range<Base>; // exposition onlyconstexpr explicit iterator(Parent& parent)requires (<Base>); // exposition onlypublic:using iterator_concept = see below; using iterator_category = see below; // not always presentusing value_type = range_value_t<range_reference_t<Base>>; using difference_type = see below; iterator() = default; constexpr iterator(iterator i)requires Const &&convertible_to<iterator_t, OuterIter> &&convertible_to<iterator_t<InnerRng>, InnerIter>; constexpr decltype(auto) operator() const { return **inner_; }constexpr InnerIter operator->() constrequires has-arrow<InnerIter> && copyable<InnerIter>; 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 && forward_range<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_)))requires indirectly_swappable<InnerIter>; };}
iterator::iterator_concept is defined as follows:
-
If ref-is-glvalue is true, Base models bidirectional_range, and range_reference_t<Base> models both bidirectional_range and common_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.
The member typedef-name iterator_category is defined if and only if ref-is-glvalue is true,Base models forward_range, andrange_reference_t<Base> models forward_range.
In that case,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 OUTERC and INNERC each model derived_from<bidirectional_iterator_tag> and range_reference_t<Base> models common_range, iterator_category denotes bidirectional_iterator_tag.
-
Otherwise, if OUTERC and INNERC each model derived_from<forward_iterator_tag>, iterator_category denotes forward_iterator_tag.
-
Otherwise, iterator_category denotes input_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 OuterIter& outer(); constexpr const OuterIter& outer() const;
Returns: outer_ if Base models forward_range; otherwise, **parent_*->outer_.
constexpr void satisfy();
Effects: Equivalent to:auto update_inner = [this](const iterator_t<Base>& x) -> auto&& {if constexpr (ref-is-glvalue) // *x is a referencereturn *x; elsereturn parent_->inner_.emplace-deref(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_.reset();
constexpr iterator(Parent& parent, OuterIter outer) requires [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Initializes outer_ with std::move(outer) andparent_ with addressof(parent); then calls satisfy().
constexpr explicit iterator(Parent& parent) requires (<Base>);
Effects: Initializes parent_ with addressof(parent); then calls satisfy().
constexpr iterator(iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<V>, OuterIter> && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<InnerRng>, InnerIter>;
Effects: Initializes outer_ with std::move(i.outer_),inner_ with std::move(i.inner_), andparent_ with i.parent_.
[Note 1:
Const can only be true when Base models forward_range.
â end note]
constexpr InnerIter operator->() const requires [has-arrow](range.utility.helpers#concept:has-arrow "25.5.2 Helper concepts [range.utility.helpers]")<InnerIter> && [copyable](concepts.object#concept:copyable "18.6 Object concepts [concepts.object]")<InnerIter>;
Effects: Equivalent to: return **inner_*;
constexpr iterator& operator++();
Let inner-range be:
Effects: Equivalent to:if (++*inner_ == ranges::end(as-lvalue(inner-range))) {++outer(); satisfy();}return *this;
constexpr void operator++(int);
Effects: Equivalent to: ++*this.
constexpr iterator operator++(int) requires ref-is-glvalue && [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<Base> && [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<range_reference_t<Base>>;
Effects: Equivalent to:auto tmp = *this;++*this;return tmp;
constexpr iterator& operator--() requires ref-is-glvalue && [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base> && [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<range_reference_t<Base>> && [common_range](range.refinements#concept:common_range "25.4.6 Other range refinements [range.refinements]")<range_reference_t<Base>>;
Effects: Equivalent to:if (outer_ == ranges::end(parent_->base_))inner_ = ranges::end(as-lvalue(--outer_));while (*inner_ == ranges::begin(as-lvalue(**outer_)))*inner_ = ranges::end(as-lvalue(--outer_));--**inner_;return *this;
constexpr iterator operator--(int) requires ref-is-glvalue && [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base> && [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<range_reference_t<Base>> && [common_range](range.refinements#concept:common_range "25.4.6 Other range refinements [range.refinements]")<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 && [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<Base> && [equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_comparable [concept.equalitycomparable]")<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_))) requires [indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept indirectly_swappable [alg.req.ind.swap]")<InnerIter>;
Effects: Equivalent to: ranges::iter_swap(*x.inner_, *y.inner_);
25.7.14.4 Class template join_view::sentinel [range.join.sentinel]
namespace std::ranges {template<input_range V>requires view && input_range<range_reference_t>templatestruct join_view::sentinel {private:using Parent = maybe-const<Const, join_view>; // exposition onlyusing Base = maybe-const<Const, V>; // exposition only sentinel_t<Base> end_ = sentinel_t<Base>(); // exposition onlypublic:sentinel() = default; constexpr explicit sentinel(Parent& parent); constexpr sentinel(sentinel s)requires Const && convertible_to<sentinel_t, sentinel_t<Base>>; templaterequires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>friend constexpr bool operator==(const iterator& 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](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;
Effects: Initializes end_ with std::move(s.end_).
template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7 Concept sentinel_for [iterator.concept.sentinel]")<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
Effects: Equivalent to: return x.outer() == y.end_;
25.7.15 Join with view [range.join.with]
25.7.15.1 Overview [range.join.with.overview]
join_with_view takes a view and a delimiter, and flattens the view, inserting every element of the delimiter in between elements of the view.
The delimiter can be a single element or a view of elements.
The name views::join_with denotes a range adaptor object ([range.adaptor.object]).
Given subexpressions E and F, the expression views::join_with(E, F) is expression-equivalent tojoin_with_view(E, F).
[Example 1: vector vs = {"the", "quick", "brown", "fox"};for (char c : vs | views::join_with('-')) { cout << c;}// The above prints the-quick-brown-fox â end example]
25.7.15.2 Class template join_with_view [range.join.with.view]
namespace std::ranges {templateconcept bidirectional-common = bidirectional_range && common_range; // exposition onlytemplate<input_range V, forward_range Pattern>requires view && input_range<range_reference_t>&& view&& concatable<range_reference_t, Pattern>class join_with_view : public view_interface<join_with_view<V, Pattern>> {using InnerRng = range_reference_t; // exposition only V base_ = V(); // exposition only**non-propagating-cache<iterator_t> outer_it_; // exposition only, present only// when non-propagating-cache<remove_cv_t<InnerRng>> inner_; // exposition only, present only// if is_reference_v<InnerRng> is false Pattern pattern_ = Pattern(); // exposition only// [range.join.with.iterator], class template join_with_view::iteratortemplate struct iterator; // exposition only// [range.join.with.sentinel], class template join_with_view::sentineltemplate struct sentinel; // exposition onlypublic: join_with_view()requires default_initializable && default_initializable = default; constexpr explicit join_with_view(V base, Pattern pattern); template<input_range R>requires constructible_from<V, views::all_t> &&constructible_from<Pattern, single_view<range_value_t<InnerRng>>>constexpr explicit join_with_view(R&& r, range_value_t<InnerRng> e); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr auto begin() {if constexpr (forward_range) {constexpr bool use_const =simple-view && is_reference_v<InnerRng> && simple-view; return iterator<use_const>{*this, ranges::begin(base_)}; }else {outer_it_ = ranges::begin(base_); return iterator{*this}; }}constexpr auto begin() constrequires forward_range &&forward_range && is_reference_v<range_reference_t> &&input_range<range_reference_t> &&concatable<range_reference_t, const Pattern> {return iterator{*this, ranges::begin(base_)}; }constexpr auto end() {if constexpr (forward_range && is_reference_v<InnerRng> && forward_range<InnerRng> &&common_range && common_range<InnerRng>)return iterator<simple-view && simple-view>{*this, ranges::end(base_)}; elsereturn sentinel<simple-view && simple-view>{*this}; }constexpr auto end() constrequires forward_range && forward_range && is_reference_v<range_reference_t> &&input_range<range_reference_t> &&concatable<range_reference_t, const Pattern> {using InnerConstRng = range_reference_t; if constexpr (forward_range &&common_range && common_range)return iterator{*this, ranges::end(base_)}; elsereturn sentinel{*this}; }}; template<class R, class P> join_with_view(R&&, P&&) -> join_with_view<views::all_t, views::all_t
>; template<input_range R> join_with_view(R&&, range_value_t<range_reference_t>)-> join_with_view<views::all_t, single_view<range_value_t<range_reference_t>>>;}
constexpr explicit join_with_view(V base, Pattern pattern);
Effects: Initializes base_ with std::move(base) andpattern_ with std::move(pattern).
template<[input_range](range.refinements#concept:input_range "25.4.6 Other range refinements [range.refinements]") R> requires [constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<V, views::all_t<R>> && [constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<Pattern, single_view<range_value_t<InnerRng>>> constexpr explicit join_with_view(R&& r, range_value_t<InnerRng> e);
Effects: Initializes base_ with views::all(std::forward(r)) andpattern_ with views::single(std::move(e)).
25.7.15.3 Class template join_with_view::iterator [range.join.with.iterator]
namespace std::ranges {template<input_range V, forward_range Pattern>requires view && input_range<range_reference_t>&& view && concatable<range_reference_t, Pattern>templateclass join_with_view<V, Pattern>::iterator {using Parent = maybe-const<Const, join_with_view>; // exposition onlyusing Base = maybe-const<Const, V>; // exposition onlyusing InnerBase = range_reference_t<Base>; // exposition onlyusing PatternBase = maybe-const<Const, Pattern>; // exposition onlyusing OuterIter = iterator_t<Base>; // exposition onlyusing InnerIter = iterator_t<InnerBase>; // exposition onlyusing PatternIter = iterator_t<PatternBase>; // exposition onlystatic constexpr bool ref-is-glvalue = is_reference_v<InnerBase>; // exposition onlyParent parent_ = nullptr; // exposition only**OuterIter outer_it_ = OuterIter(); // exposition only, present only// if Base models forward_range variant<PatternIter, InnerIter> inner_it_; // exposition onlyconstexpr iterator(Parent& parent, OuterIter outer)requires forward_range<Base>; // exposition onlyconstexpr explicit iterator(Parent& parent)requires (<Base>); // exposition onlyconstexpr OuterIter& outer(); // exposition onlyconstexpr const OuterIter& outer() const; // exposition onlyconstexpr auto& update-inner(); // exposition onlyconstexpr auto& get-inner(); // exposition onlyconstexpr void satisfy(); // exposition onlypublic:using iterator_concept = see below; using iterator_category = see below; // not always presentusing value_type = see below; using difference_type = see below; iterator() = default; constexpr iterator(iterator i)requires Const && convertible_to<iterator_t, OuterIter> &&convertible_to<iterator_t<InnerRng>, InnerIter> &&convertible_to<iterator_t, PatternIter>; constexpr decltype(auto) operator() const; constexpr iterator& operator++(); constexpr void operator++(int); constexpr iterator operator++(int)requires ref-is-glvalue && forward_iterator<OuterIter> &&forward_iterator<InnerIter>; constexpr iterator& operator--()requires ref-is-glvalue && bidirectional_range<Base> &&bidirectional-common<InnerBase> && bidirectional-common<PatternBase>; constexpr iterator operator--(int)requires ref-is-glvalue && bidirectional_range<Base> &&bidirectional-common<InnerBase> && bidirectional-common<PatternBase>; friend constexpr bool operator==(const iterator& x, const iterator& y)requires ref-is-glvalue && forward_range<Base> &&equality_comparable<InnerIter>; friend constexpr decltype(auto) iter_move(const iterator& x) {using rvalue_reference = common_reference_t< iter_rvalue_reference_t<InnerIter>,
iter_rvalue_reference_t<PatternIter>>; return visit<rvalue_reference>(ranges::iter_move, x.inner_it_); }friend constexpr void iter_swap(const iterator& x, const iterator& y)requires indirectly_swappable<InnerIter, PatternIter> { visit(ranges::iter_swap, x.inner_it_, y.inner_it_); }};}
iterator::iterator_concept is defined as follows:
-
If ref-is-glvalue is true,Base models bidirectional_range, andInnerBase and PatternBase each model bidirectional-common, then iterator_concept denotes bidirectional_iterator_tag.
-
Otherwise, if ref-is-glvalue is true andBase and InnerBase each model forward_range, then iterator_concept denotes forward_iterator_tag.
-
Otherwise, iterator_concept denotes input_iterator_tag.
The member typedef-name iterator_category is defined if and only if ref-is-glvalue is true, andBase and InnerBase each model forward_range.
In that case,iterator::iterator_category is defined as follows:
-
Let OUTERC denoteiterator_traits<OuterIter>::iterator_category, let INNERC denoteiterator_traits<InnerIter>::iterator_category, and let PATTERNC denoteiterator_traits<PatternIter>::iterator_category.
-
Ifis_reference_v<common_reference_t<iter_reference_t<InnerIter>, iter_reference_t<PatternIter>>> is false,iterator_category denotes input_iterator_tag.
-
Otherwise, if OUTERC, INNERC, and PATTERNC each model derived_from<bidirectional_iterator_tag> and InnerBase and PatternBase each model common_range,iterator_category denotes bidirectional_iterator_tag.
-
Otherwise, if OUTERC, INNERC, and PATTERNC each model derived_from<forward_iterator_tag>,iterator_category denotes forward_iterator_tag.
-
Otherwise, iterator_category denotes input_iterator_tag.
iterator::value_type denotes the type:common_type_t<iter_value_t<InnerIter>, iter_value_t<PatternIter>>
iterator::difference_type denotes the type:common_type_t< iter_difference_t<OuterIter>, iter_difference_t<InnerIter>, iter_difference_t<PatternIter>>
constexpr OuterIter& outer(); constexpr const OuterIter& outer() const;
Returns: outer_it_ if Base models forward_range; otherwise, **parent_*->outer_it_.
constexpr auto& update-inner();
Effects: Equivalent to:if constexpr (ref-is-glvalue)return as-lvalue(*outer());elsereturn parent_->inner_.emplace-deref(outer());
constexpr auto& get-inner();
Effects: Equivalent to:if constexpr (ref-is-glvalue)return as-lvalue(*outer());elsereturn **parent_*->inner_;
constexpr void satisfy();
Effects: Equivalent to:while (true) {if (inner_it_.index() == 0) {if (std::get<0>(inner_it_) != ranges::end(parent_->pattern_))break; inner_it_.template emplace<1>(ranges::begin(update-inner())); } else {if (std::get<1>(inner_it_) != ranges::end(get-inner()))break; if (++outer() == ranges::end(parent_->base_)) {if constexpr (ref-is-glvalue)inner_it_.template emplace<0>(); break; }inner_it_.template emplace<0>(ranges::begin(parent_->pattern_)); }}
[Note 1:
join_with_view iterators use the satisfy function to skip over empty inner ranges.
â end note]
constexpr iterator(Parent& parent, OuterIter outer) requires [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<Base>; constexpr explicit iterator(Parent& parent) requires (<Base>);
Effects: Initializes parent_ with addressof(parent).
For the first overload, also initializesouter_it_ with std::move(outer).
Then, equivalent to:if (outer() != ranges::end(parent_->base_)) {inner_it_.template emplace<1>(ranges::begin(update-inner())); satisfy();}
constexpr iterator(iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<V>, OuterIter> && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<InnerRng>, InnerIter> && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<Pattern>, PatternIter>;
Effects: Initializes outer_it_ withstd::move(i.outer_it_) andparent_ with i.parent_.
Then, equivalent to:if (i.inner_it_.index() == 0)inner_it_.template emplace<0>(std::get<0>(std::move(i.inner_it_)));elseinner_it_.template emplace<1>(std::get<1>(std::move(i.inner_it_)));
[Note 2:
Const can only be true when Base models forward_range.
â end note]
constexpr decltype(auto) operator*() const;
Effects: Equivalent to:using reference = common_reference_t<iter_reference_t<InnerIter>, iter_reference_t<PatternIter>>;return visit([](auto& it) -> reference { return *it; }, inner_it_);
constexpr iterator& operator++();
Effects: Equivalent to:visit([](auto& it){ ++it; }, inner_it_);satisfy();return *this;
constexpr void operator++(int);
Effects: Equivalent to ++*this.
constexpr iterator operator++(int) requires ref-is-glvalue && [forward_iterator](iterator.concept.forward#concept:forward_iterator "24.3.4.11 Concept forward_iterator [iterator.concept.forward]")<OuterIter> && [forward_iterator](iterator.concept.forward#concept:forward_iterator "24.3.4.11 Concept forward_iterator [iterator.concept.forward]")<InnerIter>;
Effects: Equivalent to:iterator tmp = *this;++*this;return tmp;
constexpr iterator& operator--() requires ref-is-glvalue && [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base> && [bidirectional-common](#concept:bidirectional-common "25.7.15.2 Class template join_with_view [range.join.with.view]")<InnerBase> && [bidirectional-common](#concept:bidirectional-common "25.7.15.2 Class template join_with_view [range.join.with.view]")<PatternBase>;
Effects: Equivalent to:if (outer_it_ == ranges::end(parent_->base_)) {auto&& inner = *--outer_it_; inner_it_.template emplace<1>(ranges::end(inner));}while (true) {if (inner_it_.index() == 0) {auto& it = std::get<0>(inner_it_); if (it == ranges::begin(parent_->pattern_)) {auto&& inner = --outer_it_; inner_it_.template emplace<1>(ranges::end(inner)); } else {break; }} else {auto& it = std::get<1>(inner_it_); auto&& inner = **outer_it_; if (it == ranges::begin(inner)) {inner_it_.template emplace<0>(ranges::end(parent_->pattern_)); } else {break; }}} visit([](auto& it){ --it; }, inner_it_);return *this;
constexpr iterator operator--(int) requires ref-is-glvalue && [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base> && [bidirectional-common](#concept:bidirectional-common "25.7.15.2 Class template join_with_view [range.join.with.view]")<InnerBase> && [bidirectional-common](#concept:bidirectional-common "25.7.15.2 Class template join_with_view [range.join.with.view]")<PatternBase>;
Effects: Equivalent to:iterator tmp = *this;--*this;return tmp;
friend constexpr bool operator==(const iterator& x, const iterator& y) requires ref-is-glvalue && [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<Base> && [equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_comparable [concept.equalitycomparable]")<InnerIter>;
Effects: Equivalent to:return x.outer_it_ == y.outer_it_ && x.inner_it_ == y.inner_it_;
25.7.15.4 Class template join_with_view::sentinel [range.join.with.sentinel]
namespace std::ranges {template<input_range V, forward_range Pattern>requires view && input_range<range_reference_t>&& view && concatable<range_reference_t, Pattern>templateclass join_with_view<V, Pattern>::sentinel {using Parent = maybe-const<Const, join_with_view>; // exposition onlyusing Base = maybe-const<Const, V>; // exposition only sentinel_t<Base> end_ = sentinel_t<Base>(); // exposition onlyconstexpr explicit sentinel(Parent& parent); // exposition onlypublic:sentinel() = default; constexpr sentinel(sentinel s)requires Const && convertible_to<sentinel_t, sentinel_t<Base>>; templaterequires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>friend constexpr bool operator==(const iterator& 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](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;
Effects: Initializes end_ with std::move(s.end_).
template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7 Concept sentinel_for [iterator.concept.sentinel]")<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
Effects: Equivalent to: return x.outer() == y.end_;
25.7.16 Lazy split view [range.lazy.split]
25.7.16.1 Overview [range.lazy.split.overview]
lazy_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::lazy_split denotes a range adaptor object ([range.adaptor.object]).
Given subexpressions E and F, the expression views::lazy_split(E, F) is expression-equivalent tolazy_split_view(E, F).
[Example 1: string str{"the quick brown fox"};for (auto word : str | views::lazy_split(' ')) {for (char ch : word) cout << ch; cout << '';}// The above prints thequickbrownfox* â end example]
25.7.16.2 Class template lazy_split_view [range.lazy.split.view]
namespace std::ranges {template struct require-constant; // exposition onlytemplateconcept tiny-range = // exposition onlysized_range &&requires { typename require-constant<remove_reference_t::size()>; } &&(remove_reference_t::size() <= 1); template<input_range V, forward_range Pattern>requires view && view &&indirectly_comparable<iterator_t, iterator_t, ranges::equal_to> &&(forward_range || tiny-range)class lazy_split_view : public view_interface<lazy_split_view<V, Pattern>> {private: V base_ = V(); // exposition only Pattern pattern_ = Pattern(); // exposition only**non-propagating-cache<iterator_t> current_; // exposition only, present only// if forward_range is false// [range.lazy.split.outer], class template lazy_split_view::outer-iteratortemplate struct outer-iterator; // exposition only// [range.lazy.split.inner], class template lazy_split_view::inner-iteratortemplate struct inner-iterator; // exposition onlypublic: lazy_split_view()requires default_initializable && default_initializable = default; constexpr explicit lazy_split_view(V base, Pattern pattern); template<input_range R>requires constructible_from<V, views::all_t> &&constructible_from<Pattern, single_view<range_value_t>>constexpr explicit lazy_split_view(R&& r, range_value_t e); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr auto begin() {if constexpr (forward_range) {return outer-iterator<simple-view && simple-view>{*this, ranges::begin(base_)}; } else {current_ = ranges::begin(base_); return outer-iterator{*this}; }}constexpr auto begin() const requires forward_range && forward_range {return outer-iterator{*this, ranges::begin(base_)}; }constexpr auto end() requires forward_range && common_range {return outer-iterator<simple-view && simple-view>{*this, ranges::end(base_)}; }constexpr auto end() const {if constexpr (forward_range && forward_range && common_range)return outer-iterator{*this, ranges::end(base_)}; elsereturn default_sentinel; }}; template<class R, class P> lazy_split_view(R&&, P&&) -> lazy_split_view<views::all_t, views::all_t
>; template<input_range R> lazy_split_view(R&&, range_value_t)-> lazy_split_view<views::all_t, single_view<range_value_t>>;}
constexpr explicit lazy_split_view(V base, Pattern pattern);
Effects: Initializes base_ with std::move(base), andpattern_ with std::move(pattern).
template<[input_range](range.refinements#concept:input_range "25.4.6 Other range refinements [range.refinements]") R> requires [constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<V, views::all_t<R>> && [constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<Pattern, single_view<range_value_t<R>>> constexpr explicit lazy_split_view(R&& r, range_value_t<R> e);
Effects: Initializes base_ with views::all(std::forward(r)), andpattern_ with views::single(std::move(e)).
25.7.16.3 Class template lazy_split_view::outer-iterator [range.lazy.split.outer]
namespace std::ranges {template<input_range V, forward_range Pattern>requires view && view &&indirectly_comparable<iterator_t, iterator_t, ranges::equal_to> &&(forward_range || tiny-range)templatestruct lazy_split_view<V, Pattern>::outer-iterator {private:using Parent = maybe-const<Const, lazy_split_view>; // exposition onlyusing Base = maybe-const<Const, V>; // exposition onlyParent parent_ = nullptr; // exposition only iterator_t<Base> current_ = iterator_t<Base>(); // exposition only, present only// if V models forward_rangebool trailing_empty_ = false; // exposition onlypublic:using iterator_concept = conditional_t<forward_range<Base>, forward_iterator_tag, input_iterator_tag>; using iterator_category = input_iterator_tag; // present only if Base// models forward_range// [range.lazy.split.outer.value], class lazy_split_view::outer-iterator::value_typestruct value_type; using difference_type = range_difference_t<Base>; outer-iterator() = default; constexpr explicit outer-iterator(Parent& parent)requires (<Base>); constexpr outer-iterator(Parent& parent, iterator_t<Base> current)requires forward_range<Base>; constexpr outer-iterator(outer-iterator i)requires Const && convertible_to<iterator_t, 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 specifications in [range.lazy.split] refer to the notional membercurrent of outer-iterator.
current is equivalent to current_ if V models forward_range, and **parent_*->current_ otherwise.
constexpr explicit outer-iterator(Parent& parent) requires (<Base>);
Effects: Initializes parent_ with addressof(parent).
constexpr outer-iterator(Parent& parent, iterator_t<Base> current) requires [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Initializes parent_ with addressof(parent) and current_ with std::move(current).
constexpr outer-iterator(outer-iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<V>, iterator_t<Base>>;
Effects: Initializes parent_ with i.parent_,current_ with std::move(i.current_), andtrailing_empty_ with i.trailing_empty_.
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) {trailing_empty_ = false; return *this;}const auto [pbegin, pend] = subrange{parent_->pattern_};if (pbegin == pend) ++current;else if constexpr (tiny-range) {current = ranges::find(std::move(current), end, *pbegin); if (current != end) {++current; if (current == end)trailing_empty_ = true; }}else {do {auto [b, p] = ranges::mismatch(current, end, pbegin, pend); if (p == pend) {current = b; if (current == end)trailing_empty_ = true; 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](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:return x.current_ == y.current_ && x.trailing_empty_ == y.trailing_empty_;
friend constexpr bool operator==(const outer-iterator& x, default_sentinel_t);
Effects: Equivalent to:return x.current == ranges::end(x.parent_->base_) && !x.trailing_empty_;
25.7.16.4 Class lazy_split_view::outer-iterator::value_type [range.lazy.split.outer.value]
namespace std::ranges {template<input_range V, forward_range Pattern>requires view && view &&indirectly_comparable<iterator_t, iterator_t, ranges::equal_to> &&(forward_range || tiny-range)templatestruct lazy_split_view<V, Pattern>::outer-iterator::value_type : view_interface<value_type> {private:outer-iterator i_ = outer-iterator(); // exposition onlyconstexpr explicit value_type(outer-iterator i); // exposition onlypublic:constexpr inner-iterator begin() const; constexpr default_sentinel_t end() const noexcept; };}
constexpr explicit value_type(outer-iterator i);
Effects: Initializes i_ with std::move(i).
constexpr inner-iterator<Const> begin() const;
Effects: Equivalent to: return inner-iterator{i_};
constexpr default_sentinel_t end() const noexcept;
Effects: Equivalent to: return default_sentinel;
25.7.16.5 Class template lazy_split_view::inner-iterator [range.lazy.split.inner]
namespace std::ranges {template<input_range V, forward_range Pattern>requires view && view &&indirectly_comparable<iterator_t, iterator_t, ranges::equal_to> &&(forward_range || tiny-range)templatestruct lazy_split_view<V, Pattern>::inner-iterator {private:using Base = maybe-const<Const, V>; // exposition only**outer-iterator i_ = outer-iterator(); // exposition onlybool incremented_ = false; // exposition onlypublic:using iterator_concept = typename outer-iterator::iterator_concept; using iterator_category = see below; // present only if Base// models forward_rangeusing value_type = range_value_t<Base>; using difference_type = range_difference_t<Base>; inner-iterator() = default; constexpr explicit inner-iterator(outer-iterator i); constexpr const iterator_t<Base>& base() const & noexcept; constexpr iterator_t<Base> base() && requires forward_range; constexpr decltype(auto) operator*() const { return **i_*.current; }constexpr inner-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 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>>; };}
If Base does not model forward_range there is no member iterator_category.
Otherwise, the typedef-name iterator_category denotes:
forward_iterator_tag ifiterator_traits<iterator_t<Base>>::iterator_category modelsderived_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 const iterator_t<Base>& base() const & noexcept;
Effects: Equivalent to: return i_.current;
constexpr iterator_t<Base> base() && requires [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<V>;
Effects: Equivalent to: return std::move(i_.current);
constexpr inner-iterator& operator++();
Effects: Equivalent to:incremented_ = true;if constexpr (<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](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<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) {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](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept indirectly_swappable [alg.req.ind.swap]")<iterator_t<Base>>;
Effects: Equivalent toranges::iter_swap(x.i_.current, y.i_.current).
25.7.17 Split view [range.split]
25.7.17.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 tosplit_view(E, F).
[Example 1: string str{"the quick brown fox"};for (auto word : views::split(str, ' ')) { cout << string_view(word) << '';}// The above prints thequickbrownfox* â end example]
25.7.17.2 Class template split_view [range.split.view]
namespace std::ranges {template<forward_range V, forward_range Pattern>requires view && view &&indirectly_comparable<iterator_t, iterator_t, ranges::equal_to>class split_view : public view_interface<split_view<V, Pattern>> {private: V base_ = V(); // exposition only Pattern pattern_ = Pattern(); // exposition only// [range.split.iterator], class split_view::iteratorstruct iterator; // exposition only// [range.split.sentinel], class split_view::sentinelstruct sentinel; // exposition onlypublic: split_view()requires default_initializable && default_initializable = default; constexpr explicit split_view(V base, Pattern pattern); template<forward_range R>requires constructible_from<V, views::all_t> &&constructible_from<Pattern, single_view<range_value_t>>constexpr explicit split_view(R&& r, range_value_t e); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr iterator begin(); constexpr auto end() {if constexpr (common_range) {return iterator{*this, ranges::end(base_), {}}; } else {return sentinel{*this}; }}constexpr subrange<iterator_t> find-next(iterator_t); // exposition only}; template<class R, class P> split_view(R&&, P&&) -> split_view<views::all_t, views::all_t
>; template<forward_range R> split_view(R&&, range_value_t)-> split_view<views::all_t, single_view<range_value_t>>;}
constexpr explicit split_view(V base, Pattern pattern);
Effects: Initializes base_ with std::move(base), andpattern_ with std::move(pattern).
template<[forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]") R> requires [constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<V, views::all_t<R>> && [constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<Pattern, single_view<range_value_t<R>>> constexpr explicit split_view(R&& r, range_value_t<R> e);
Effects: Initializes base_ with views::all(std::forward(r)), andpattern_ with views::single(std::move(e)).
constexpr iterator begin();
Returns: {*this, ranges::begin(base_), find-next(ranges::begin(base_))}.
Remarks: In order to provide the amortized constant time complexity required by the range concept, this function caches the result within the split_view for use on subsequent calls.
constexpr subrange<iterator_t<V>> find-next(iterator_t<V> it);
Effects: Equivalent to:auto [b, e] = ranges::search(subrange(it, ranges::end(base_)), pattern_);if (b != ranges::end(base_) && ranges::empty(pattern_)) {++b; ++e;}return {b, e};
25.7.17.3 Class split_view::iterator [range.split.iterator]
namespace std::ranges {template<forward_range V, forward_range Pattern>requires view && view &&indirectly_comparable<iterator_t, iterator_t, ranges::equal_to>class split_view<V, Pattern>::iterator {private: split_view* parent_ = nullptr; // exposition only iterator_t cur_ = iterator_t(); // exposition only subrange<iterator_t> next_ = subrange<iterator_t>(); // exposition onlybool trailing_empty_ = false; // exposition onlypublic:using iterator_concept = forward_iterator_tag; using iterator_category = input_iterator_tag; using value_type = subrange<iterator_t>; using difference_type = range_difference_t; iterator() = default; constexpr iterator(split_view& parent, iterator_t current, subrange<iterator_t> next); constexpr iterator_t base() const; constexpr value_type operator*() const; constexpr iterator& operator++(); constexpr iterator operator++(int); friend constexpr bool operator==(const iterator& x, const iterator& y); };}
constexpr iterator(split_view& parent, iterator_t<V> current, subrange<iterator_t<V>> next);
Effects: Initializes parent_ with addressof(parent),cur_ with std::move(current), andnext_ with std::move(next).
constexpr iterator_t<V> base() const;
Effects: Equivalent to: return cur_;
constexpr value_type operator*() const;
Effects: Equivalent to: return {cur_, next_.begin()};
constexpr iterator& operator++();
Effects: Equivalent to:cur_ = next_.begin();if (cur_ != ranges::end(parent_->base_)) {cur_ = next_.end(); if (cur_ == ranges::end(parent_->base_)) {trailing_empty_ = true; next_ = {cur_, cur_}; } else {next_ = parent_->find-next(cur_); }} else {trailing_empty_ = false;}return *this;
constexpr iterator operator++(int);
Effects: Equivalent to:auto tmp = *this;++*this;return tmp;
friend constexpr bool operator==(const iterator& x, const iterator& y);
Effects: Equivalent to:return x.cur_ == y.cur_ && x.trailing_empty_ == y.trailing_empty_;
25.7.17.4 Class split_view::sentinel [range.split.sentinel]
namespace std::ranges {template<forward_range V, forward_range Pattern>requires view && view &&indirectly_comparable<iterator_t, iterator_t, ranges::equal_to>struct split_view<V, Pattern>::sentinel {private: sentinel_t end_ = sentinel_t(); // exposition onlypublic:sentinel() = default; constexpr explicit sentinel(split_view& parent); friend constexpr bool operator==(const iterator& x, const sentinel& y); };}
constexpr explicit sentinel(split_view& parent);
Effects: Initializes end_ with ranges::end(parent.base_).
friend constexpr bool operator==(const iterator& x, const sentinel& y);
Effects: Equivalent to: return x.cur_ == y.end_ && !x.trailing_empty_;
25.7.18 Concat view [range.concat]
25.7.18.1 Overview [range.concat.overview]
concat_view presents a view that concatenates all the underlying ranges.
The name views::concat denotes a customization point object ([customization.point.object]).
Given a pack of subexpressions Es..., the expression views::concat(Es...) is expression-equivalent to
views::all(Es...) if Es is a pack with only one element whose type models input_range,
otherwise, concat_view(Es...).
[Example 1: vector v1{1, 2, 3}, v2{4, 5}, v3{}; array a{6, 7, 8};auto s = views::single(9);for (auto&& i : views::concat(v1, v2, v3, a, s)) { print("{} ", i); // prints 1 2 3 4 5 6 7 8 9} â end example]
25.7.18.2 Class template concat_view [range.concat.view]
namespace std::ranges {template<class... Rs>using concat-reference-t = common_reference_t<range_reference_t...>; // exposition onlytemplate<class... Rs>using concat-value-t = common_type_t<range_value_t...>; // exposition onlytemplate<class... Rs>using concat-rvalue-reference-t = // exposition only common_reference_t<range_rvalue_reference_t...>; template<class... Rs>concept concat-indirectly-readable = see below; // exposition onlytemplate<class... Rs>concept concatable = see below; // exposition onlytemplate<bool Const, class... Rs>concept concat-is-random-access = see below; // exposition onlytemplate<bool Const, class... Rs>concept concat-is-bidirectional = see below; // exposition onlytemplate<input_range... Views>requires (view && ...) && (sizeof...(Views) > 0) &&concatable<Views...>class concat_view : public view_interface<concat_view<Views...>> { tuple<Views...> views_; // exposition only// [range.concat.iterator], class template concat_view::iteratortemplate class iterator; // exposition onlypublic:constexpr concat_view() = default; constexpr explicit concat_view(Views... views); constexpr iterator begin() requires (!(simple-view && ...)); constexpr iterator begin() constrequires (range && ...) && concatable; constexpr auto end() requires (!(simple-view && ...)); constexpr auto end() constrequires (range && ...) && concatable; constexpr auto size() requires (sized_range && ...); constexpr auto size() const requires (sized_range && ...); }; template<class... R> concat_view(R&&...) -> concat_view<views::all_t...>;}
template<class... Rs> concept [concat-indirectly-readable](#concept:concat-indirectly-readable "25.7.18.2 Class template concat_view [range.concat.view]") = see below; // exposition only
The exposition-only concat-indirectly-readable concept is equivalent to:template<class Ref, class RRef, class It>concept concat-indirectly-readable-impl = // exposition onlyrequires (const It it) {{ *it } -> convertible_to; { ranges::iter_move(it) } -> convertible_to; };
template<class... Rs>concept concat-indirectly-readable = // exposition onlycommon_reference_with<concat-reference-t<Rs...>&&, concat-value-t<Rs...>&> &&common_reference_with<concat-reference-t<Rs...>&&, concat-rvalue-reference-t<Rs...>&&> &&common_reference_with<concat-rvalue-reference-t<Rs...>&&, concat-value-t<Rs...> const&> &&(concat-indirectly-readable-impl<concat-reference-t<Rs...>, concat-rvalue-reference-t<Rs...>, iterator_t> && ...);
template<class... Rs> concept [concatable](#concept:concatable "25.7.18.2 Class template concat_view [range.concat.view]") = see below; // exposition only
The exposition-only concatable concept is equivalent to:template<class... Rs>concept concatable = requires { // exposition onlytypename concat-reference-t<Rs...>; typename concat-value-t<Rs...>; typename concat-rvalue-reference-t<Rs...>; } && concat-indirectly-readable<Rs...>;
template<bool Const, class... Rs> concept [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2 Class template concat_view [range.concat.view]") = see below; // exposition only
Let Fs be the pack that consists of all elements of Rs except the last element, then concat-is-random-access is equivalent to:template<bool Const, class... Rs>concept concat-is-random-access = // exposition onlyall-random-access<Const, Rs...> &&(common_range<maybe-const<Const, Fs>> && ...);
template<bool Const, class... Rs> concept [concat-is-bidirectional](#concept:concat-is-bidirectional "25.7.18.2 Class template concat_view [range.concat.view]") = see below; // exposition only
Let Fs be the pack that consists of all elements of Rs except the last element, then concat-is-bidirectional is equivalent to:template<bool Const, class... Rs>concept concat-is-bidirectional = // exposition onlyall-bidirectional<Const, Rs...> &&(common_range<maybe-const<Const, Fs>> && ...);
constexpr explicit concat_view(Views... views);
Effects: Initializes views_ with std::move(views)....
constexpr iterator<false> begin() requires (!([simple-view](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]")<Views> && ...)); constexpr iterator<true> begin() const requires ([range](range.range#concept:range "25.4.2 Ranges [range.range]")<const Views> && ...) && [concatable](#concept:concatable "25.7.18.2 Class template concat_view [range.concat.view]")<const Views...>;
Effects: Let is-const betrue for the const-qualified overload, andfalse otherwise.
Equivalent to:iterator<is-const> it(this, in_place_index<0>, ranges::begin(std::get<0>(views_))); it.template satisfy<0>();return it;
constexpr auto end() requires (!([simple-view](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]")<Views> && ...)); constexpr auto end() const requires ([range](range.range#concept:range "25.4.2 Ranges [range.range]")<const Views> && ...) && [concatable](#concept:concatable "25.7.18.2 Class template concat_view [range.concat.view]")<const Views...>;
Effects: Let is-const betrue for the const-qualified overload, andfalse otherwise.
Equivalent to:constexpr auto N = sizeof...(Views);if constexpr (common_range<maybe-const<is-const, Views...[N - 1]>>) {return iterator<is-const>(this, in_place_index<N - 1>, ranges::end(std::get<N - 1>(views_)));} else {return default_sentinel;}
constexpr auto size() requires ([sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<Views> && ...); constexpr auto size() const requires ([sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<const Views> && ...);
Effects: Equivalent to:return apply([](auto... sizes) {using CT = make-unsigned-like-t<common_type_t<decltype(sizes)...>>; return (CT(sizes) + ...); }, tuple-transform(ranges::size, views_));
25.7.18.3 Class concat_view::iterator [range.concat.iterator]
namespace std::ranges {template<input_range... Views>requires (view && ...) && (sizeof...(Views) > 0) &&concatable<Views...>templateclass concat_view<Views...>::iterator {public:using iterator_category = see below; // not always presentusing iterator_concept = see below; using value_type = concat-value-t<maybe-const<Const, Views>...>; using difference_type = common_type_t<range_difference_t<maybe-const<Const, Views>>...>; private:using base-iter = // exposition only variant<iterator_t<maybe-const<Const, Views>>...>; maybe-const<Const, concat_view>* parent_ = nullptr; // exposition only**base-iter it_; // exposition onlytemplate<size_t N>constexpr void satisfy(); // exposition onlytemplate<size_t N>constexpr void prev(); // exposition onlytemplate<size_t N>constexpr void advance-fwd(difference_type offset, // exposition only difference_type steps); template<size_t N>constexpr void advance-bwd(difference_type offset, // exposition only difference_type steps); template<class... Args>constexpr explicit iterator(maybe-const<Const, concat_view>* parent, // exposition only Args&&... args)requires constructible_from<base-iter, Args&&...>; public:iterator() = default; constexpr iterator(iterator i)requires Const && (convertible_to<iterator_t, iterator_t> && ...); constexpr decltype(auto) operator*() const; constexpr iterator& operator++(); constexpr void operator++(int); constexpr iterator operator++(int)requires all-forward<Const, Views...>; constexpr iterator& operator--()requires concat-is-bidirectional<Const, Views...>; constexpr iterator operator--(int)requires concat-is-bidirectional<Const, Views...>; constexpr iterator& operator+=(difference_type n)requires concat-is-random-access<Const, Views...>; constexpr iterator& operator-=(difference_type n)requires concat-is-random-access<Const, Views...>; constexpr decltype(auto) operator[](difference_type n) constrequires concat-is-random-access<Const, Views...>; friend constexpr bool operator==(const iterator& x, const iterator& y)requires (equality_comparable<iterator_t<maybe-const<Const, Views>>> && ...); friend constexpr bool operator==(const iterator& it, default_sentinel_t); friend constexpr bool operator<(const iterator& x, const iterator& y)requires all-random-access<Const, Views...>; friend constexpr bool operator>(const iterator& x, const iterator& y)requires all-random-access<Const, Views...>; friend constexpr bool operator<=(const iterator& x, const iterator& y)requires all-random-access<Const, Views...>; friend constexpr bool operator>=(const iterator& x, const iterator& y)requires all-random-access<Const, Views...>; friend constexpr auto operator<=>(const iterator& x, const iterator& y)requires (all-random-access<Const, Views...> &&(three_way_comparable<iterator_t<maybe-const<Const, Views>>> && ...)); friend constexpr iterator operator+(const iterator& it, difference_type n)requires concat-is-random-access<Const, Views...>; friend constexpr iterator operator+(difference_type n, const iterator& it)requires concat-is-random-access<Const, Views...>; friend constexpr iterator operator-(const iterator& it, difference_type n)requires concat-is-random-access<Const, Views...>; friend constexpr difference_type operator-(const iterator& x, const iterator& y)requires concat-is-random-access<Const, Views...>; friend constexpr difference_type operator-(const iterator& x, default_sentinel_t)requires see below; friend constexpr difference_type operator-(default_sentinel_t, const iterator& x)requires see below; friend constexpr decltype(auto) iter_move(const iterator& it) noexcept(see below); friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(see below)requires see below; };}
iterator::iterator_concept is defined as follows:
-
Ifconcat-is-random-access<Const, Views...> is modeled, then iterator_concept denotes random_access_iterator_tag.
-
Otherwise, ifconcat-is-bidirectional<Const, Views...> is modeled, then iterator_concept denotes bidirectional_iterator_tag.
-
Otherwise, ifall-forward<Const, Views...> is modeled, then iterator_concept denotes forward_iterator_tag.
-
Otherwise, iterator_concept denotes input_iterator_tag.
The member typedef-name iterator_category is defined if and only ifall-forward<Const, Views...> is modeled.
In that case,iterator::iterator_category is defined as follows:
-
Ifis_reference_v<concat-reference-t<maybe-const<Const, Views>...>> is false, then iterator_category denotes input_iterator_tag.
-
Otherwise, let Cs denote the pack of typesiterator_traits<iterator_t<maybe-const<Const, Views>>>::iterator_category....
-
If(derived_from<Cs, random_access_iterator_tag> && ...) && concat-is-random-access<Const, Views...> is true,iterator_category denotes random_access_iterator_tag.
-
Otherwise, if(derived_from<Cs, bidirectional_iterator_tag> && ...) && concat-is-bidirectional<Const, Views...> is true,iterator_category denotes bidirectional_iterator_tag.
-
Otherwise, if(derived_from<Cs, forward_iterator_tag> && ...) is true,iterator_category denotes forward_iterator_tag.
-
Otherwise, iterator_category denotes input_iterator_tag.
-
template<size_t N> constexpr void satisfy();
Effects: Equivalent to:if constexpr (N < (sizeof...(Views) - 1)) {if (std::get(it_) == ranges::end(std::get(parent_->views_))) {it_.template emplace<N + 1>(ranges::begin(std::get<N + 1>(parent_->views_))); satisfy<N + 1>(); }}
template<size_t N> constexpr void prev();
Effects: Equivalent to:if constexpr (N == 0) {--std::get<0>(it_);} else {if (std::get(it_) == ranges::begin(std::get(parent_->views_))) {it_.template emplace<N - 1>(ranges::end(std::get<N - 1>(parent_->views_))); prev<N - 1>(); } else {--std::get(it_); }}
template<size_t N> constexpr void advance-fwd(difference_type offset, difference_type steps);
Effects: Equivalent to:using underlying_diff_type = iter_difference_t<variant_alternative_t<N, base-iter>>;if constexpr (N == sizeof...(Views) - 1) { std::get(it_) += static_cast<underlying_diff_type>(steps);} else {auto n_size = ranges::distance(std::get(parent_->views_)); if (offset + steps < n_size) { std::get(it_) += static_cast<underlying_diff_type>(steps); } else {it_.template emplace<N + 1>(ranges::begin(std::get<N + 1>(parent_->views_))); advance-fwd<N + 1>(0, offset + steps - n_size); }}
template<size_t N> constexpr void advance-bwd(difference_type offset, difference_type steps);
Effects: Equivalent to:using underlying_diff_type = iter_difference_t<variant_alternative_t<N, base-iter>>;if constexpr (N == 0) { std::get(it_) -= static_cast<underlying_diff_type>(steps);} else {if (offset >= steps) { std::get(it_) -= static_cast<underlying_diff_type>(steps); } else {auto prev_size = ranges::distance(std::get<N - 1>(parent_->views_)); it_.template emplace<N - 1>(ranges::end(std::get<N - 1>(parent_->views_))); advance-bwd<N - 1>(prev_size, steps - offset); }}
template<class... Args> constexpr explicit iterator(maybe-const<Const, concat_view>* parent, Args&&... args) requires [constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<base-iter, Args&&...>;
Effects: Initializes parent_ with parent, and initializes it_ with std::forward(args)....
constexpr iterator(iterator<!Const> it) requires Const && ([convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<Views>, iterator_t<const Views>> && ...);
Preconditions: it.it_.valueless_by_exception() is false.
Effects: Initializes parent_ with it.parent_, and let i be it.it_.index(), initializes it_ withbase-iter(in_place_index, std::get(std::move(it.it_))).
constexpr decltype(auto) operator*() const;
Preconditions: it_.valueless_by_exception() is false.
Effects: Equivalent to:using reference = concat-reference-t<maybe-const<Const, Views>...>;return std::visit([](auto&& it) -> reference { return *it; }, it_);
constexpr iterator& operator++();
Preconditions: it_.valueless_by_exception() is false.
Effects: Let i be it_.index().
Equivalent to:++std::get(it_);satisfy();return *this;
constexpr void operator++(int);
Effects: Equivalent to:++*this;
constexpr iterator operator++(int) requires [all-forward](#concept:all-forward "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...>;
Effects: Equivalent to:auto tmp = *this;++*this;return tmp;
constexpr iterator& operator--() requires [concat-is-bidirectional](#concept:concat-is-bidirectional "25.7.18.2 Class template concat_view [range.concat.view]")<Const, Views...>;
Preconditions: it_.valueless_by_exception() is false.
Effects: Let i be it_.index().
Equivalent to:prev();return *this;
constexpr iterator operator--(int) requires [concat-is-bidirectional](#concept:concat-is-bidirectional "25.7.18.2 Class template concat_view [range.concat.view]")<Const, Views...>;
Effects: Equivalent to:auto tmp = *this;--*this;return tmp;
constexpr iterator& operator+=(difference_type n) requires [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2 Class template concat_view [range.concat.view]")<Const, Views...>;
Preconditions: it_.valueless_by_exception() is false.
Effects: Let i be it_.index().
Equivalent to:if (n > 0) {advance-fwd(std::get(it_) - ranges::begin(std::get(parent_->views_)), n);} else if (n < 0) {advance-bwd(std::get(it_) - ranges::begin(std::get(parent_->views_)), -n);}return *this;
constexpr iterator& operator-=(difference_type n) requires [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2 Class template concat_view [range.concat.view]")<Const, Views...>;
Effects: Equivalent to:*this += -n;return *this;
constexpr decltype(auto) operator[](difference_type n) const requires [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2 Class template concat_view [range.concat.view]")<Const, Views...>;
Effects: Equivalent to:return *((*this) + n);
friend constexpr bool operator==(const iterator& x, const iterator& y) requires ([equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_comparable [concept.equalitycomparable]")<iterator_t<maybe-const<Const, Views>>> && ...);
Preconditions: x.it_.valueless_by_exception() andy.it_.valueless_by_exception() are each false.
Effects: Equivalent to:return x.it_ == y.it_;
friend constexpr bool operator==(const iterator& it, default_sentinel_t);
Preconditions: it.it_.valueless_by_exception() is false.
Effects: Equivalent to:constexpr auto last_idx = sizeof...(Views) - 1;return it.it_.index() == last_idx && std::get<last_idx>(it.it_) == ranges::end(std::get<last_idx>(it.parent_->views_));
friend constexpr bool operator<(const iterator& x, const iterator& y) requires [all-random-access](#concept:all-random-access "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...>; friend constexpr bool operator>(const iterator& x, const iterator& y) requires [all-random-access](#concept:all-random-access "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...>; friend constexpr bool operator<=(const iterator& x, const iterator& y) requires [all-random-access](#concept:all-random-access "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...>; friend constexpr bool operator>=(const iterator& x, const iterator& y) requires [all-random-access](#concept:all-random-access "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...>; friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires ([all-random-access](#concept:all-random-access "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...> && ([three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4 Concept three_way_comparable [cmp.concept]")<iterator_t<maybe-const<Const, Views>>> && ...));
Preconditions: x.it_.valueless_by_exception() andy.it_.valueless_by_exception() are each false.
Let op be the operator.
Effects: Equivalent to:return x.it_ op y.it_;
friend constexpr iterator operator+(const iterator& it, difference_type n) requires [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2 Class template concat_view [range.concat.view]")<Const, Views...>;
Effects: Equivalent to:auto temp = it; temp += n;return temp;
friend constexpr iterator operator+(difference_type n, const iterator& it) requires [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2 Class template concat_view [range.concat.view]")<Const, Views...>;
Effects: Equivalent to:return it + n;
friend constexpr iterator operator-(const iterator& it, difference_type n) requires [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2 Class template concat_view [range.concat.view]")<Const, Views...>;
Effects: Equivalent to:auto temp = it; temp -= n;return temp;
friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2 Class template concat_view [range.concat.view]")<Const, Views...>;
Preconditions: x.it_.valueless_by_exception() andy.it_.valueless_by_exception() are each false.
Effects: Letix denote x.it_.index() andiy denote y.it_.index().
If ix > iy, letdy beranges::distance(std::get(y.it_), ranges::end(std::get(y.parent_->views_))),dx beranges::distance(ranges::begin(std::get(x.parent_->views_)), std::get(x.it_)). Let s denote the sum of the sizes of all the rangesstd::get(x.parent_->views_) for every integer i in the range [iy + 1, ix) if there is any, and0 otherwise, of type difference_type, equivalent to:return dy + s + dx;
otherwise, if ix < iy is true, equivalent to:return -(y - x);
otherwise, equivalent to:return std::get(x.it_) - std::get(y.it_);
friend constexpr difference_type operator-(const iterator& x, default_sentinel_t) requires see below;
Preconditions: x.it_.valueless_by_exception() is false.
Effects: Letix denote x.it_.index(),dx beranges::distance(std::get(x.it_), ranges::end(std::get(x.parent_->views_))).
Let s denote the sum of the sizes of all the rangesstd::get(x.parent_->views_) for every integer i in the range [ix + 1, sizeof...(Views)) if there is any, and0 otherwise, of type difference_type, equivalent to:return -(dx + s);
Remarks: Let Fs be the pack that consists of all elements of Views except the first element, the expression in the requires-clause is equivalent to:(sized_sentinel_for<sentinel_t<maybe-const<Const, Views>>, iterator_t<maybe-const<Const, Views>>> && ...) &&(sized_range<maybe-const<Const, Fs>> && ...)
friend constexpr difference_type operator-(default_sentinel_t, const iterator& x) requires see below;
Effects: Equivalent to:return -(x - default_sentinel);
Remarks: Let Fs be the pack that consists of all elements of Views except the first element, the expression in the requires-clause is equivalent to:(sized_sentinel_for<sentinel_t<maybe-const<Const, Views>>, iterator_t<maybe-const<Const, Views>>> && ...) &&(sized_range<maybe-const<Const, Fs>> && ...)
friend constexpr decltype(auto) iter_move(const iterator& it) noexcept(see below);
Preconditions: it.it_.valueless_by_exception() is false.
Effects: Equivalent to:return std::visit([](const auto& i)-> concat-rvalue-reference-t<maybe-const<Const, Views>...> {return ranges::iter_move(i); }, it.it_);
Remarks: The exception specification is equivalent to:((is_nothrow_invocable_v<decltype(ranges::iter_move), const iterator_t<maybe-const<Const, Views>>&> && is_nothrow_convertible_v<range_rvalue_reference_t<maybe-const<Const, Views>>, concat-rvalue-reference-t<maybe-const<Const, Views>...>>) &&...)
friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(see below) requires see below;
Preconditions: x.it_.valueless_by_exception() andy.it_.valueless_by_exception() are each false.
Effects: Equivalent to:std::visit([&](const auto& it1, const auto& it2) {if constexpr (is_same_v<decltype(it1), decltype(it2)>) { ranges::iter_swap(it1, it2); } else { ranges::swap(*x, *y); }}, x.it_, y.it_);
Remarks: The exception specification is equivalent to(noexcept(ranges::swap(*x, *y)) && ... && noexcept(ranges::iter_swap(its, its))) where its is a pack of lvalues of typeconst iterator_t<maybe-const<Const, Views>> respectively.
The expression in the requires-clause is equivalent toswappable_with<iter_reference_t<iterator>, iter_reference_t<iterator>> &&(... && indirectly_swappable<iterator_t<maybe-const<Const, Views>>>)
25.7.19 Counted view [range.counted]
A counted view presents a view of the elements of the counted range ([iterator.requirements.general]) i+[0, n) 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.
If decltype((F)) does not modelconvertible_to,views::counted(E, F) is ill-formed.
[Note 1:
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<size_t>(static_cast(F))).
-
Otherwise, if T models random_access_iterator, then subrange(E, E + static_cast(F)), except that E is evaluated only once.
-
Otherwise,subrange(counted_iterator(E, F), default_sentinel).
25.7.20 Common view [range.common]
25.7.20.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 1:
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 1: // Legacy algorithm:template size_t count(ForwardIterator first, ForwardIterator last);
template<forward_range R>void my_algo(R&& r) {auto&& common = views::common(r); auto cnt = count(common.begin(), common.end()); // ...} â end example]
25.7.20.2 Class template common_view [range.common.view]
namespace std::ranges {template<view V>requires ( && copyable<iterator_t>)class common_view : public view_interface<common_view> {private: V base_ = V(); // exposition onlypublic: common_view() requires default_initializable = default; constexpr explicit common_view(V r); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr auto begin() requires (
) {if constexpr (random_access_range && sized_range)return ranges::begin(base_); elsereturn common_iterator<iterator_t, sentinel_t>(ranges::begin(base_)); }constexpr auto begin() const requires range {if constexpr (random_access_range && sized_range)return ranges::begin(base_); elsereturn common_iterator<iterator_t, sentinel_t>(ranges::begin(base_)); }constexpr auto end() requires (
) {if constexpr (random_access_range && sized_range)return ranges::begin(base_) + ranges::distance(base_); elsereturn common_iterator<iterator_t, sentinel_t>(ranges::end(base_)); }constexpr auto end() const requires range {if constexpr (random_access_range && sized_range)return ranges::begin(base_) + ranges::distance(base_); elsereturn common_iterator<iterator_t, sentinel_t>(ranges::end(base_)); }constexpr auto size() requires sized_range {return ranges::size(base_); }constexpr auto size() const requires sized_range {return ranges::size(base_); }constexpr auto reserve_hint() requires approximately_sized_range {return ranges::reserve_hint(base_); }constexpr auto reserve_hint() const requires approximately_sized_range {return ranges::reserve_hint(base_); }}; template common_view(R&&) -> common_view<views::all_t>;}
constexpr explicit common_view(V base);
Effects: Initializes base_ with std::move(base).
25.7.21 Reverse view [range.reverse]
25.7.21.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 expressionviews::reverse(E) is expression-equivalent to:
-
If the type of E is a (possibly cv-qualified) specialization of reverse_view, then E.base().
-
Otherwise, if the type of E is cv subrange<reverse_iterator, reverse_iterator, K> for some iterator type I and value K of type subrange_kind,
if K is subrange_kind::sized, thensubrange<I, I, K>(E.end().base(), E.begin().base(), E.size());
otherwise, subrange<I, I, K>(E.end().base(), E.begin().base()).
However, in either case E is evaluated only once.
[Example 1: vector is {0,1,2,3,4};for (int i : is | views::reverse) cout << i << ' '; // prints 4 3 2 1 0 â end example]
25.7.21.2 Class template reverse_view [range.reverse.view]
namespace std::ranges {template<view V>requires bidirectional_rangeclass reverse_view : public view_interface<reverse_view> {private: V base_ = V(); // exposition onlypublic: reverse_view() requires default_initializable = default; constexpr explicit reverse_view(V r); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr reverse_iterator<iterator_t> begin(); constexpr reverse_iterator<iterator_t> begin() requires common_range; constexpr auto begin() const requires common_range; constexpr reverse_iterator<iterator_t> end(); constexpr auto end() const requires common_range; constexpr auto size() requires sized_range {return ranges::size(base_); }constexpr auto size() const requires sized_range {return ranges::size(base_); }constexpr auto reserve_hint() requires approximately_sized_range {return ranges::reserve_hint(base_); }constexpr auto reserve_hint() const requires approximately_sized_range {return ranges::reserve_hint(base_); }}; template reverse_view(R&&) -> reverse_view<views::all_t>;}
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 thereverse_view for use on subsequent calls.
constexpr reverse_iterator<iterator_t<V>> begin() requires [common_range](range.refinements#concept:common_range "25.4.6 Other range refinements [range.refinements]")<V>; constexpr auto begin() const requires [common_range](range.refinements#concept:common_range "25.4.6 Other range refinements [range.refinements]")<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](range.refinements#concept:common_range "25.4.6 Other range refinements [range.refinements]")<const V>;
Effects: Equivalent to: return make_reverse_iterator(ranges::begin(base_));
25.7.22 As const view [range.as.const]
25.7.22.1 Overview [range.as.const.overview]
as_const_view presents a view of an underlying sequence as constant.
That is, the elements of an as_const_view cannot be modified.
The name views::as_const denotes a range adaptor object ([range.adaptor.object]).
Let E be an expression, let T be decltype((E)), and let U be remove_cvref_t.
The expression views::as_const(E) is expression-equivalent to:
-
If views::all_t models constant_range, then views::all(E).
-
Otherwise, if U denotes empty_view for some type X, then auto(views::empty).
-
Otherwise, if U denotes span<X, Extent> for some type X and some extent Extent, then span<const X, Extent>(E).
-
Otherwise, if U denotes ref_view for some type X andconst X models constant_range, then ref_view(static_cast<const X&>(E.base())).
-
Otherwise, if E is an lvalue,const U models constant_range, andU does not model view, then ref_view(static_cast<const U&>(E)).
-
Otherwise, as_const_view(E).
[Example 1: template<constant_range R>void cant_touch_this(R&&);
vector hammer = {'m', 'c'}; span beat = hammer; cant_touch_this(views::as_const(beat)); // will not modify the elements of hammer â end example]
25.7.22.2 Class template as_const_view [range.as.const.view]
namespace std::ranges {template<view V>requires input_rangeclass as_const_view : public view_interface<as_const_view> { V base_ = V(); // exposition onlypublic: as_const_view() requires default_initializable = default; constexpr explicit as_const_view(V base); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr auto begin() requires () { return ranges::cbegin(base_); }constexpr auto begin() const requires range { return ranges::cbegin(base_); }constexpr auto end() requires (
) { return ranges::cend(base_); }constexpr auto end() const requires range { return ranges::cend(base_); }constexpr auto size() requires sized_range { return ranges::size(base_); }constexpr auto size() const requires sized_range { return ranges::size(base_); }constexpr auto reserve_hint() requires approximately_sized_range{ return ranges::reserve_hint(base_); }constexpr auto reserve_hint() const requires approximately_sized_range{ return ranges::reserve_hint(base_); }}; template as_const_view(R&&) -> as_const_view<views::all_t>;}
constexpr explicit as_const_view(V base);
Effects: Initializes base_ with std::move(base).
25.7.23 Elements view [range.elements]
25.7.23.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 Nth element of the adapted view's value-type.
The name views::elements denotes a range adaptor object ([range.adaptor.object]).
Given a subexpression E and constant expression N, the expression views::elements(E) is expression-equivalent toelements_view<views::all_t<decltype((E))>, N>{E}.
[Example 1: auto historical_figures = map{ pair{"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<R, 0>, and is useful for extracting keys from associative containers.
[Example 2: auto names = historical_figures | views::keys;for (auto&& name : names) { cout << name << ' '; // prints Babbage Hamilton Lovelace Turing } â end example]
values_view is an alias for elements_view<R, 1>, and is useful for extracting values from associative containers.
[Example 3: auto is_even = [](const auto x) { return x % 2 == 0; }; cout << ranges::count_if(historical_figures | views::values, is_even); // prints 2 â end example]
25.7.23.2 Class template elements_view [range.elements.view]
namespace std::ranges {template<class T, size_t N>concept has-tuple-element = // exposition onlytuple-like && N < tuple_size_v; template<class T, size_t N>concept returnable-element = // exposition only is_reference_v || move_constructible<tuple_element_t<N, T>>; template<input_range V, size_t N>requires view && has-tuple-element<range_value_t, N> &&has-tuple-element<remove_reference_t<range_reference_t>, N> &&returnable-element<range_reference_t, N>class elements_view : public view_interface<elements_view<V, N>> {public: elements_view() requires default_initializable = default; constexpr explicit elements_view(V base); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr auto begin() requires (){ return iterator(ranges::begin(base_)); }constexpr auto begin() const requires range{ return iterator(ranges::begin(base_)); }constexpr auto end() requires (
&&
){ return sentinel{ranges::end(base_)}; }constexpr auto end() requires (
&& common_range){ return iterator{ranges::end(base_)}; }constexpr auto end() const requires range{ return sentinel{ranges::end(base_)}; }constexpr auto end() const requires common_range{ return iterator{ranges::end(base_)}; }constexpr auto size() requires sized_range{ return ranges::size(base_); }constexpr auto size() const requires sized_range{ return ranges::size(base_); }constexpr auto reserve_hint() requires approximately_sized_range{ return ranges::reserve_hint(base_); }constexpr auto reserve_hint() const requires approximately_sized_range{ return ranges::reserve_hint(base_); }private:// [range.elements.iterator], class template elements_view::iteratortemplate class iterator; // exposition only// [range.elements.sentinel], class template elements_view::sentineltemplate class sentinel; // exposition only V base_ = V(); // exposition only};}
constexpr explicit elements_view(V base);
Effects: Initializes base_ with std::move(base).
25.7.23.3 Class template elements_view::iterator [range.elements.iterator]
namespace std::ranges {template<input_range V, size_t N>requires view && has-tuple-element<range_value_t, N> &&has-tuple-element<remove_reference_t<range_reference_t>, N> &&returnable-element<range_reference_t, N>templateclass elements_view<V, N>::iterator {using Base = maybe-const<Const, V>; // exposition only iterator_t<Base> current_ = iterator_t<Base>(); // exposition onlystatic constexpr decltype(auto) get-element(const iterator_t<Base>& i); // exposition onlypublic:using iterator_concept = see below; using iterator_category = see below; // not always presentusing value_type = remove_cvref_t<tuple_element_t<N, range_value_t<Base>>>; using difference_type = range_difference_t<Base>; iterator() requires default_initializable<iterator_t<Base>> = default; constexpr explicit iterator(iterator_t<Base> current); constexpr iterator(iterator i)requires Const && convertible_to<iterator_t, iterator_t<Base>>; constexpr const iterator_t<Base>& base() const & noexcept; constexpr iterator_t<Base> base() &&; constexpr decltype(auto) operator*() const{ return get-element(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 x)requires random_access_range<Base>; constexpr iterator& operator-=(difference_type x)requires random_access_range<Base>; constexpr decltype(auto) operator[](difference_type n) constrequires random_access_range<Base>{ return get-element(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+(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 sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>; };}
The member typedef-name iterator_concept is defined as follows:
-
If Base models random_access_range, then iterator_concept denotes random_access_iterator_tag.
-
Otherwise, if Base models bidirectional_range, then iterator_concept denotes bidirectional_iterator_tag.
-
Otherwise, if Base models forward_range, then iterator_concept denotes forward_iterator_tag.
-
Otherwise, iterator_concept denotes input_iterator_tag.
The member typedef-name iterator_category is defined if and only if Base models forward_range.
In that case, iterator_category is defined as follows: Let C denote the typeiterator_traits<iterator_t<Base>>::iterator_category.
-
If std::get(**current_*) is an rvalue,iterator_category denotes input_iterator_tag.
-
Otherwise, if C models derived_from<random_access_iterator_tag>,iterator_category denotes random_access_iterator_tag.
-
Otherwise, iterator_category denotes C.
static constexpr decltype(auto) get-element(const iterator_t<Base>& i);
Effects: Equivalent to:if constexpr (is_reference_v<range_reference_t<Base>>) {return std::get(*i);} else {using E = remove_cv_t<tuple_element_t<N, range_reference_t<Base>>>; return static_cast(std::get(*i));}
constexpr explicit iterator(iterator_t<Base> current);
Effects: Initializes current_ with std::move(current).
constexpr iterator(iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<V>, iterator_t<Base>>;
Effects: Initializes current_ with std::move(i.current_).
constexpr const iterator_t<Base>& base() const & noexcept;
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](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto temp = *this;++current_;return temp;
constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:--current_;return *this;
constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto temp = *this;--current_;return temp;
constexpr iterator& operator+=(difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:current_ += n;return *this;
constexpr iterator& operator-=(difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:current_ -= n;return *this;
friend constexpr bool operator==(const iterator& x, const iterator& y) requires [equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_comparable [concept.equalitycomparable]")<Base>;
Effects: Equivalent to: return x.current_ == y.current_;
friend constexpr bool operator<(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return x.current_ < y.current_;
friend constexpr bool operator>(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return y < x;
friend constexpr bool operator<=(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return !(y < x);
friend constexpr bool operator>=(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return !(x < y);
friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base> && [three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4 Concept three_way_comparable [cmp.concept]")<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](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return iterator{x} += y;
friend constexpr iterator operator+(difference_type x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return y + x;
friend constexpr iterator operator-(const iterator& x, difference_type y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return iterator{x} -= y;
friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<iterator_t<Base>, iterator_t<Base>>;
Effects: Equivalent to: return x.current_ - y.current_;
25.7.23.4 Class template elements_view::sentinel [range.elements.sentinel]
namespace std::ranges {template<input_range V, size_t N>requires view && has-tuple-element<range_value_t, N> &&has-tuple-element<remove_reference_t<range_reference_t>, N> &&returnable-element<range_reference_t, N>templateclass elements_view<V, N>::sentinel {private:using Base = maybe-const<Const, V>; // exposition only sentinel_t<Base> end_ = sentinel_t<Base>(); // exposition onlypublic:sentinel() = default; constexpr explicit sentinel(sentinel_t<Base> end); constexpr sentinel(sentinel other)requires Const && convertible_to<sentinel_t, sentinel_t<Base>>; constexpr sentinel_t<Base> base() const; templaterequires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>friend constexpr bool operator==(const iterator& x, const sentinel& y); templaterequires sized_sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>friend constexpr range_difference_t<maybe-const<OtherConst, V>>operator-(const iterator& x, const sentinel& y); templaterequires sized_sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>friend constexpr range_difference_t<maybe-const<OtherConst, V>>operator-(const sentinel& x, const iterator& y); };}
constexpr explicit sentinel(sentinel_t<Base> end);
Effects: Initializes end_ with end.
constexpr sentinel(sentinel<!Const> other) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<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_;
template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7 Concept sentinel_for [iterator.concept.sentinel]")<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
Effects: Equivalent to: return x.current_ == y.end_;
template<bool OtherConst> requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr range_difference_t<maybe-const<OtherConst, V>> operator-(const iterator<OtherConst>& x, const sentinel& y);
Effects: Equivalent to: return x.current_ - y.end_;
template<bool OtherConst> requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr range_difference_t<maybe-const<OtherConst, V>> operator-(const sentinel& x, const iterator<OtherConst>& y);
Effects: Equivalent to: return x.end_ - y.current_;
25.7.24 Enumerate view [range.enumerate]
25.7.24.1 Overview [range.enumerate.overview]
enumerate_view is a view whose elements represent both the position and value from a sequence of elements.
The name views::enumerate denotes a range adaptor object ([range.adaptor.object]).
Given a subexpression E, the expression views::enumerate(E) is expression-equivalent toenumerate_view<views::all_t<decltype((E))>>(E).
[Example 1: vector vec{ 1, 2, 3 };for (auto [index, value] : views::enumerate(vec)) cout << index << ":" << value << ' '; // prints 0:1 1:2 2:3 â end example]
25.7.24.2 Class template enumerate_view [range.enumerate.view]
namespace std::ranges {template<view V>requires range-with-movable-referencesclass enumerate_view : public view_interface<enumerate_view> { V base_ = V(); // exposition only// [range.enumerate.iterator], class template enumerate_view::iteratortemplateclass iterator; // exposition only// [range.enumerate.sentinel], class template enumerate_view::sentineltemplateclass sentinel; // exposition onlypublic:constexpr enumerate_view() requires default_initializable = default; constexpr explicit enumerate_view(V base); constexpr auto begin() requires (){ return iterator(ranges::begin(base_), 0); }constexpr auto begin() const requires range-with-movable-references{ return iterator(ranges::begin(base_), 0); }constexpr auto end() requires (
) {if constexpr (forward_range && common_range && sized_range)return iterator(ranges::end(base_), ranges::distance(base_)); elsereturn sentinel(ranges::end(base_)); }constexpr auto end() const requires range-with-movable-references {if constexpr (forward_range && common_range && sized_range)return iterator(ranges::end(base_), ranges::distance(base_)); elsereturn sentinel(ranges::end(base_)); }constexpr auto size() requires sized_range{ return ranges::size(base_); }constexpr auto size() const requires sized_range{ return ranges::size(base_); }constexpr auto reserve_hint() requires approximately_sized_range{ return ranges::reserve_hint(base_); }constexpr auto reserve_hint() const requires approximately_sized_range{ return ranges::reserve_hint(base_); }constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }}; template enumerate_view(R&&) -> enumerate_view<views::all_t>;}
constexpr explicit enumerate_view(V base);
Effects: Initializes base_ with std::move(base).
25.7.24.3 Class template enumerate_view::iterator [range.enumerate.iterator]
namespace std::ranges {template<view V>requires range-with-movable-referencestemplateclass enumerate_view::iterator {using Base = maybe-const<Const, V>; // exposition onlypublic:using iterator_category = input_iterator_tag; using iterator_concept = see below; using difference_type = range_difference_t<Base>; using value_type = tuple<difference_type, range_value_t<Base>>; private:using reference-type = // exposition only tuple<difference_type, range_reference_t<Base>>; iterator_t<Base> current_ = iterator_t<Base>(); // exposition only difference_type pos_ = 0; // exposition onlyconstexpr explicititerator(iterator_t<Base> current, difference_type pos); // exposition onlypublic:iterator() requires default_initializable<iterator_t<Base>> = default; constexpr iterator(iterator i)requires Const && convertible_to<iterator_t, iterator_t<Base>>; constexpr const iterator_t<Base>& base() const & noexcept; constexpr iterator_t<Base> base() &&; constexpr difference_type index() const noexcept; constexpr auto operator*() const {return reference-type(pos_, **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 x)requires random_access_range<Base>; constexpr iterator& operator-=(difference_type x)requires random_access_range<Base>; constexpr auto operator[](difference_type n) constrequires random_access_range<Base>{ return reference-type(pos_ + n, current_[n]); }friend constexpr bool operator==(const iterator& x, const iterator& y) noexcept; friend constexpr strong_ordering operator<=>(const iterator& x, const iterator& y) noexcept; 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) noexcept; friend constexpr auto iter_move(const iterator& i)noexcept(noexcept(ranges::iter_move(i.current_)) && is_nothrow_move_constructible_v<range_rvalue_reference_t<Base>>) {return tuple<difference_type, range_rvalue_reference_t<Base>>(i.pos_, ranges::iter_move(i.current_)); }};}
The member typedef-nameiterator::iterator_concept is defined as follows:
-
If Base models random_access_range, then iterator_concept denotes random_access_iterator_tag.
-
Otherwise, if Base models bidirectional_range, then iterator_concept denotes bidirectional_iterator_tag.
-
Otherwise, if Base models forward_range, then iterator_concept denotes forward_iterator_tag.
-
Otherwise, iterator_concept denotes input_iterator_tag.
constexpr explicit iterator(iterator_t<Base> current, difference_type pos);
Effects: Initializes current_ with std::move(current) andpos_ with pos.
constexpr iterator(iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<V>, iterator_t<Base>>;
Effects: Initializes current_ with std::move(i.current_) andpos_ with i.pos_.
constexpr const iterator_t<Base>& base() const & noexcept;
Effects: Equivalent to: return current_;
constexpr iterator_t<Base> base() &&;
Effects: Equivalent to: return std::move(current_);
constexpr difference_type index() const noexcept;
Effects: Equivalent to: return pos_;
constexpr iterator& operator++();
Effects: Equivalent to:++current_;++pos_;return *this;
constexpr void operator++(int);
Effects: Equivalent to ++*this.
constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto temp = *this;++*this;return temp;
constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:--current_;--pos_;return *this;
constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto temp = *this;--*this;return temp;
constexpr iterator& operator+=(difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:current_ += n;pos_ += n;return *this;
constexpr iterator& operator-=(difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:current_ -= n;pos_ -= n;return *this;
friend constexpr bool operator==(const iterator& x, const iterator& y) noexcept;
Effects: Equivalent to: return x.pos_ == y.pos_;
friend constexpr strong_ordering operator<=>(const iterator& x, const iterator& y) noexcept;
Effects: Equivalent to: return x.pos_ <=> y.pos_;
friend constexpr iterator operator+(const iterator& x, difference_type y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto temp = x; temp += y;return temp;
friend constexpr iterator operator+(difference_type x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return y + x;
friend constexpr iterator operator-(const iterator& x, difference_type y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto temp = x; temp -= y;return temp;
friend constexpr difference_type operator-(const iterator& x, const iterator& y) noexcept;
Effects: Equivalent to: return x.pos_ - y.pos_;
25.7.24.4 Class template enumerate_view::sentinel [range.enumerate.sentinel]
namespace std::ranges {template<view V>requires range-with-movable-referencestemplateclass enumerate_view::sentinel {using Base = maybe-const<Const, V>; // exposition only sentinel_t<Base> end_ = sentinel_t<Base>(); // exposition onlyconstexpr explicit sentinel(sentinel_t<Base> end); // exposition onlypublic:sentinel() = default; constexpr sentinel(sentinel other)requires Const && convertible_to<sentinel_t, sentinel_t<Base>>; constexpr sentinel_t<Base> base() const; templaterequires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>friend constexpr bool operator==(const iterator& x, const sentinel& y); templaterequires sized_sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>friend constexpr range_difference_t<maybe-const<OtherConst, V>>operator-(const iterator& x, const sentinel& y); templaterequires sized_sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>friend constexpr range_difference_t<maybe-const<OtherConst, V>>operator-(const sentinel& x, const iterator& y); };}
constexpr explicit sentinel(sentinel_t<Base> end);
Effects: Initializes end_ with std::move(end).
constexpr sentinel(sentinel<!Const> other) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<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_;
template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7 Concept sentinel_for [iterator.concept.sentinel]")<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
Effects: Equivalent to: return x.current_ == y.end_;
template<bool OtherConst> requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr range_difference_t<maybe-const<OtherConst, V>> operator-(const iterator<OtherConst>& x, const sentinel& y);
Effects: Equivalent to: return x.current_ - y.end_;
template<bool OtherConst> requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr range_difference_t<maybe-const<OtherConst, V>> operator-(const sentinel& x, const iterator<OtherConst>& y);
Effects: Equivalent to: return x.end_ - y.current_;
25.7.25 Zip view [range.zip]
25.7.25.1 Overview [range.zip.overview]
zip_view takes any number of views and produces a view of tuples of references to the corresponding elements of the constituent views.
The name views::zip denotes a customization point object ([customization.point.object]).
Given a pack of subexpressions Es..., the expression views::zip(Es...) is expression-equivalent to
auto(views::empty<tuple<>>) if Es is an empty pack,
otherwise, zip_view<views::all_t<decltype((Es))>...>(Es...).
[Example 1: vector v = {1, 2}; list l = {'a', 'b', 'c'};
auto z = views::zip(v, l); range_reference_t<decltype(z)> f = z.front(); // f is a tuple<int&, char&>// that refers to the first element of v and lfor (auto&& [x, y] : z) { cout << '(' << x << ", " << y << ") "; // prints (1, a) (2, b)} â end example]
25.7.25.2 Class template zip_view [range.zip.view]
namespace std::ranges {template<class... Rs>concept zip-is-common = // exposition only(sizeof...(Rs) == 1 && (common_range && ...)) ||(!(bidirectional_range && ...) && (common_range && ...)) ||((random_access_range && ...) && (sized_range && ...)); template<input_range... Views>requires (view && ...) && (sizeof...(Views) > 0)class zip_view : public view_interface<zip_view<Views...>> { tuple<Views...> views_; // exposition only// [range.zip.iterator], class template zip_view::iteratortemplate class iterator; // exposition only// [range.zip.sentinel], class template zip_view::sentineltemplate class sentinel; // exposition onlypublic: zip_view() = default; constexpr explicit zip_view(Views... views); constexpr auto begin() requires (!(simple-view && ...)) {return iterator(tuple-transform(ranges::begin, views_)); }constexpr auto begin() const requires (range && ...) {return iterator(tuple-transform(ranges::begin, views_)); }constexpr auto end() requires (!(simple-view && ...)) {if constexpr (<Views...>) {return sentinel(tuple-transform(ranges::end, views_)); } else if constexpr ((random_access_range && ...)) {return begin() + iter_difference_t<iterator>(size()); } else {return iterator(tuple-transform(ranges::end, views_)); }}constexpr auto end() const requires (range && ...) {if constexpr (
) {return sentinel(tuple-transform(ranges::end, views_)); } else if constexpr ((random_access_range && ...)) {return begin() + iter_difference_t<iterator>(size()); } else {return iterator(tuple-transform(ranges::end, views_)); }}constexpr auto size() requires (sized_range && ...); constexpr auto size() const requires (sized_range && ...); }; template<class... Rs> zip_view(Rs&&...) -> zip_view<views::all_t...>;}
Two zip_view objects have the same underlying sequence if and only if the corresponding elements of views_ are equal ([concepts.equality]) and have the same underlying sequence.
[Note 1:
In particular, comparison of iterators obtained from zip_view objects that do not have the same underlying sequence is not required to produce meaningful results ([iterator.concept.forward]).
â end note]
constexpr explicit zip_view(Views... views);
Effects: Initializes views_ with std::move(views)....
constexpr auto size() requires ([sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<Views> && ...); constexpr auto size() const requires ([sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<const Views> && ...);
Effects: Equivalent to:return apply([](auto... sizes) {using CT = make-unsigned-like-t<common_type_t<decltype(sizes)...>>; return ranges::min({CT(sizes)...});}, tuple-transform(ranges::size, views_));
25.7.25.3 Class template zip_view::iterator [range.zip.iterator]
namespace std::ranges {template<input_range... Views>requires (view && ...) && (sizeof...(Views) > 0)templateclass zip_view<Views...>::iterator { tuple<iterator_t<maybe-const<Const, Views>>...> current_; // exposition onlyconstexpr explicit iterator(tuple<iterator_t<maybe-const<Const, Views>>...>); // exposition onlypublic:using iterator_category = input_iterator_tag; // not always presentusing iterator_concept = see below; using value_type = tuple<range_value_t<maybe-const<Const, Views>>...>; using difference_type = common_type_t<range_difference_t<maybe-const<Const, Views>>...>; iterator() = default; constexpr iterator(iterator i)requires Const && (convertible_to<iterator_t, iterator_t> && ...); constexpr auto operator*() const; constexpr iterator& operator++(); constexpr void operator++(int); constexpr iterator operator++(int) requires all-forward<Const, Views...>; constexpr iterator& operator--() requires all-bidirectional<Const, Views...>; constexpr iterator operator--(int) requires all-bidirectional<Const, Views...>; constexpr iterator& operator+=(difference_type x)requires all-random-access<Const, Views...>; constexpr iterator& operator-=(difference_type x)requires all-random-access<Const, Views...>; constexpr auto operator[](difference_type n) constrequires all-random-access<Const, Views...>; friend constexpr bool operator==(const iterator& x, const iterator& y)requires (equality_comparable<iterator_t<maybe-const<Const, Views>>> && ...); friend constexpr auto operator<=>(const iterator& x, const iterator& y)requires all-random-access<Const, Views...>; friend constexpr iterator operator+(const iterator& i, difference_type n)requires all-random-access<Const, Views...>; friend constexpr iterator operator+(difference_type n, const iterator& i)requires all-random-access<Const, Views...>; friend constexpr iterator operator-(const iterator& i, difference_type n)requires all-random-access<Const, Views...>; friend constexpr difference_type operator-(const iterator& x, const iterator& y)requires (sized_sentinel_for<iterator_t<maybe-const<Const, Views>>, iterator_t<maybe-const<Const, Views>>> && ...); friend constexpr auto iter_move(const iterator& i) noexcept(see below); friend constexpr void iter_swap(const iterator& l, const iterator& r) noexcept(see below)requires (indirectly_swappable<iterator_t<maybe-const<Const, Views>>> && ...); };}
iterator::iterator_concept is defined as follows:
-
If all-random-access<Const, Views...> is modeled, then iterator_concept denotes random_access_iterator_tag.
-
Otherwise, if all-bidirectional<Const, Views...> is modeled, then iterator_concept denotes bidirectional_iterator_tag.
-
Otherwise, if all-forward<Const, Views...> is modeled, then iterator_concept denotes forward_iterator_tag.
-
Otherwise, iterator_concept denotes input_iterator_tag.
iterator::iterator_category is present if and only if all-forward<Const, Views...> is modeled.
If the invocation of any non-const member function of iterator exits via an exception, the iterator acquires a singular value.
constexpr explicit iterator(tuple<iterator_t<maybe-const<Const, Views>>...> current);
Effects: Initializes current_ with std::move(current).
constexpr iterator(iterator<!Const> i) requires Const && ([convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<Views>, iterator_t<const Views>> && ...);
Effects: Initializes current_ with std::move(i.current_).
constexpr auto operator*() const;
Effects: Equivalent to:return tuple-transform([](auto& i) -> decltype(auto) { return *i; }, current_);
constexpr iterator& operator++();
Effects: Equivalent to:tuple-for-each([](auto& i) { ++i; }, current_);return *this;
constexpr void operator++(int);
Effects: Equivalent to ++*this.
constexpr iterator operator++(int) requires [all-forward](#concept:all-forward "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...>;
Effects: Equivalent to:auto tmp = *this;++*this;return tmp;
constexpr iterator& operator--() requires [all-bidirectional](#concept:all-bidirectional "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...>;
Effects: Equivalent to:tuple-for-each([](auto& i) { --i; }, current_);return *this;
constexpr iterator operator--(int) requires [all-bidirectional](#concept:all-bidirectional "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...>;
Effects: Equivalent to:auto tmp = *this;--*this;return tmp;
constexpr iterator& operator+=(difference_type x) requires [all-random-access](#concept:all-random-access "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...>;
Effects: Equivalent to:tuple-for-each([&](I& i) { i += iter_difference_t(x); }, current_);return *this;
constexpr iterator& operator-=(difference_type x) requires [all-random-access](#concept:all-random-access "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...>;
Effects: Equivalent to:tuple-for-each([&](I& i) { i -= iter_difference_t(x); }, current_);return *this;
constexpr auto operator[](difference_type n) const requires [all-random-access](#concept:all-random-access "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...>;
Effects: Equivalent to:return tuple-transform([&](I& i) -> decltype(auto) {return i[iter_difference_t(n)];}, current_);
friend constexpr bool operator==(const iterator& x, const iterator& y) requires ([equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_comparable [concept.equalitycomparable]")<iterator_t<maybe-const<Const, Views>>> && ...);
Returns:
-
x.current_ == y.current_ if all-bidirectional<Const, Views...> is true.
-
Otherwise, true if there exists an integer 0â¤i<sizeof...(Views) such that bool(std::get(x.current_) == std::get(y.current_)) is true. [Note 1: This allows zip_view to model common_range when all constituent views model common_range. â end note]
-
Otherwise, false.
friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires [all-random-access](#concept:all-random-access "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...>;
Returns: x.current_ <=> y.current_.
friend constexpr iterator operator+(const iterator& i, difference_type n) requires [all-random-access](#concept:all-random-access "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...>; friend constexpr iterator operator+(difference_type n, const iterator& i) requires [all-random-access](#concept:all-random-access "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...>;
Effects: Equivalent to:auto r = i; r += n;return r;
friend constexpr iterator operator-(const iterator& i, difference_type n) requires [all-random-access](#concept:all-random-access "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, Views...>;
Effects: Equivalent to:auto r = i; r -= n;return r;
friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires ([sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<iterator_t<maybe-const<Const, Views>>, iterator_t<maybe-const<Const, Views>>> && ...);
Let DIST(i) be difference_type(std::get(x.current_) - std::get(y.current_)).
Returns: The value with the smallest absolute value among DIST(n) for all integers 0â¤n<sizeof...(Views).
friend constexpr auto iter_move(const iterator& i) noexcept(see below);
Effects: Equivalent to:return tuple-transform(ranges::iter_move, i.current_);
Remarks: The exception specification is equivalent to:(noexcept(ranges::iter_move(declval<const iterator_t<maybe-const<Const, Views>>&>())) && ...) &&(is_nothrow_move_constructible_v<range_rvalue_reference_t<maybe-const<Const, Views>>> && ...)
friend constexpr void iter_swap(const iterator& l, const iterator& r) noexcept(see below) requires ([indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept indirectly_swappable [alg.req.ind.swap]")<iterator_t<maybe-const<Const, Views>>> && ...);
Effects: For every integer 0â¤i<sizeof...(Views), performs:ranges::iter_swap(std::get(l.current_), std::get(r.current_))
Remarks: The exception specification is equivalent to the logical and of the following expressions:noexcept(ranges::iter_swap(std::get(l.current_), std::get(r.current_))) for every integer 0â¤i<sizeof...(Views).
25.7.25.4 Class template zip_view::sentinel [range.zip.sentinel]
namespace std::ranges {template<input_range... Views>requires (view && ...) && (sizeof...(Views) > 0)templateclass zip_view<Views...>::sentinel { tuple<sentinel_t<maybe-const<Const, Views>>...> end_; // exposition onlyconstexpr explicit sentinel(tuple<sentinel_t<maybe-const<Const, Views>>...> end); // exposition onlypublic:sentinel() = default; constexpr sentinel(sentinel i)requires Const && (convertible_to<sentinel_t, sentinel_t> && ...); templaterequires (sentinel_for<sentinel_t<maybe-const<Const, Views>>, iterator_t<maybe-const<OtherConst, Views>>> && ...)friend constexpr bool operator==(const iterator& x, const sentinel& y); templaterequires (sized_sentinel_for<sentinel_t<maybe-const<Const, Views>>, iterator_t<maybe-const<OtherConst, Views>>> && ...)friend constexpr common_type_t<range_difference_t<maybe-const<OtherConst, Views>>...>operator-(const iterator& x, const sentinel& y); templaterequires (sized_sentinel_for<sentinel_t<maybe-const<Const, Views>>, iterator_t<maybe-const<OtherConst, Views>>> && ...)friend constexpr common_type_t<range_difference_t<maybe-const<OtherConst, Views>>...>operator-(const sentinel& y, const iterator& x); };}
constexpr explicit sentinel(tuple<sentinel_t<maybe-const<Const, Views>>...> end);
Effects: Initializes end_ with end.
constexpr sentinel(sentinel<!Const> i) requires Const && ([convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<sentinel_t<Views>, sentinel_t<const Views>> && ...);
Effects: Initializes end_ with std::move(i.end_).
template<bool OtherConst> requires ([sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7 Concept sentinel_for [iterator.concept.sentinel]")<sentinel_t<maybe-const<Const, Views>>, iterator_t<maybe-const<OtherConst, Views>>> && ...) friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
Returns: true if there exists an integer 0â¤i<sizeof...(Views) such that bool(std::get(x.current_) == std::get(y.end_)) is true.
Otherwise, false.
template<bool OtherConst> requires ([sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<maybe-const<Const, Views>>, iterator_t<maybe-const<OtherConst, Views>>> && ...) friend constexpr common_type_t<range_difference_t<maybe-const<OtherConst, Views>>...> operator-(const iterator<OtherConst>& x, const sentinel& y);
Let D be the return type.
Let DIST(i) beD(std::get(x.current_) - std::get(y.end_)).
Returns: The value with the smallest absolute value among DIST(n) for all integers 0â¤n<sizeof...(Views).
template<bool OtherConst> requires ([sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<maybe-const<Const, Views>>, iterator_t<maybe-const<OtherConst, Views>>> && ...) friend constexpr common_type_t<range_difference_t<maybe-const<OtherConst, Views>>...> operator-(const sentinel& y, const iterator<OtherConst>& x);
Effects: Equivalent to: return -(x - y);
25.7.26 Zip transform view [range.zip.transform]
25.7.26.1 Overview [range.zip.transform.overview]
zip_transform_view takes an invocable object and any number of views and produces a view whose Mth element is the result of applying the invocable object to the Mth elements of all views.
The name views::zip_transform denotes a customization point object ([customization.point.object]).
Let F be a subexpression, and let Es... be a pack of subexpressions.
If move_constructible &®ular_invocable<FD&> is false, or if decay_t<invoke_result_t<FD&>> is not an object type,views::zip_transform(F, Es...) is ill-formed.
Otherwise, the expression views::zip_transform(F, Es...) is expression-equivalent to((void)F, auto(views::empty<decay_t<invoke_result_t<FD&>>>))
-
Otherwise, the expression views::zip_transform(F, Es...) is expression-equivalent to zip_transform_view(F, Es...).
[Example 1: vector v1 = {1, 2}; vector v2 = {4, 5, 6};
for (auto i : views::zip_transform(plus(), v1, v2)) { cout << i << ' '; // prints 5 7} â end example]
25.7.26.2 Class template zip_transform_view [range.zip.transform.view]
namespace std::ranges {template<move_constructible F, input_range... Views>requires (view && ...) && (sizeof...(Views) > 0) && is_object_v &®ular_invocable<F&, range_reference_t...> &&can-reference<invoke_result_t<F&, range_reference_t...>>class zip_transform_view : public view_interface<zip_transform_view<F, Views...>> {movable-box fun_; // exposition only zip_view<Views...> zip_; // exposition onlyusing InnerView = zip_view<Views...>; // exposition onlytemplateusing ziperator = iterator_t<maybe-const<Const, InnerView>>; // exposition onlytemplateusing zentinel = sentinel_t<maybe-const<Const, InnerView>>; // exposition only// [range.zip.transform.iterator], class template zip_transform_view::iteratortemplate class iterator; // exposition only// [range.zip.transform.sentinel], class template zip_transform_view::sentineltemplate class sentinel; // exposition onlypublic: zip_transform_view() = default; constexpr explicit zip_transform_view(F fun, Views... views); constexpr auto begin() { return iterator(*this, zip_.begin()); }constexpr auto begin() constrequires range<const InnerView> &®ular_invocable<const F&, range_reference_t...> {return iterator(*this, zip_.begin()); }constexpr auto end() {if constexpr (common_range<InnerView>) {return iterator(*this, zip_.end()); } else {return sentinel(zip_.end()); }}constexpr auto end() constrequires range<const InnerView> &®ular_invocable<const F&, range_reference_t...> {if constexpr (common_range<const InnerView>) {return iterator(*this, zip_.end()); } else {return sentinel(zip_.end()); }}constexpr auto size() requires sized_range<InnerView> {return zip_.size(); }constexpr auto size() const requires sized_range<const InnerView> {return zip_.size(); }}; template<class F, class... Rs> zip_transform_view(F, Rs&&...) -> zip_transform_view<F, views::all_t...>;}
constexpr explicit zip_transform_view(F fun, Views... views);
Effects: Initializes fun_ with std::move(fun) andzip_ with std::move(views)....
25.7.26.3 Class template zip_transform_view::iterator [range.zip.transform.iterator]
namespace std::ranges {template<move_constructible F, input_range... Views>requires (view && ...) && (sizeof...(Views) > 0) && is_object_v &®ular_invocable<F&, range_reference_t...> &&can-reference<invoke_result_t<F&, range_reference_t...>>templateclass zip_transform_view<F, Views...>::iterator {using Parent = maybe-const<Const, zip_transform_view>; // exposition onlyusing Base = maybe-const<Const, InnerView>; // exposition onlyParent parent_ = nullptr; // exposition only**ziperator inner_; // exposition onlyconstexpr iterator(Parent& parent, ziperator inner); // exposition onlypublic:using iterator_category = see below; // not always presentusing iterator_concept = typename ziperator::iterator_concept; using value_type = remove_cvref_t<invoke_result_t<maybe-const<Const, F>&, range_reference_t<maybe-const<Const, Views>>...>>; using difference_type = range_difference_t<Base>; iterator() = default; constexpr iterator(iterator i)requires Const && convertible_to<ziperator, ziperator>; constexpr decltype(auto) operator() const noexcept(see below); 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 x) requires random_access_range<Base>; constexpr iterator& operator-=(difference_type x) requires random_access_range<Base>; constexpr decltype(auto) operator[](difference_type n) constrequires random_access_range<Base>; friend constexpr bool operator==(const iterator& x, const iterator& y)requires equality_comparable<ziperator>; friend constexpr auto operator<=>(const iterator& x, const iterator& y)requires random_access_range<Base>; friend constexpr iterator operator+(const iterator& i, difference_type n)requires random_access_range<Base>; friend constexpr iterator operator+(difference_type n, const iterator& i)requires random_access_range<Base>; friend constexpr iterator operator-(const iterator& i, difference_type n)requires random_access_range<Base>; friend constexpr difference_type operator-(const iterator& x, const iterator& y)requires sized_sentinel_for<ziperator, ziperator>; };}
The member typedef-nameiterator::iterator_category is defined if and only if Base models forward_range.
In that case,iterator::iterator_category is defined as follows:
Ifinvoke_result_t<maybe-const<Const, F>&, range_reference_t<maybe-const<Const, Views>>...> is not a reference,iterator_category denotes input_iterator_tag.
Otherwise, let Cs denote the pack of typesiterator_traits<iterator_t<maybe-const<Const, Views>>>::iterator_category.... * (1.2.1)
If ([derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_from [concept.derived]")<Cs, random_access_iterator_tag> && ...) is true,iterator_category denotes random_access_iterator_tag[.](#range.zip.transform.iterator-1.2.1.sentence-1)
-
Otherwise, if (derived_from<Cs, bidirectional_iterator_tag> && ...) is true,iterator_category denotes bidirectional_iterator_tag.
-
Otherwise, if (derived_from<Cs, forward_iterator_tag> && ...) is true,iterator_category denotes forward_iterator_tag.
-
Otherwise, iterator_category denotes input_iterator_tag.
constexpr iterator(Parent& parent, ziperator<Const> inner);
Effects: Initializes parent_ with addressof(parent) andinner_ with std::move(inner).
constexpr iterator(iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<ziperator<false>, ziperator<Const>>;
Effects: Initializes parent_ with i.parent_ andinner_ with std::move(i.inner_).
constexpr decltype(auto) operator*() const noexcept(see below);
Effects: Equivalent to:return apply([&](const auto&... iters) -> decltype(auto) {return invoke(**parent_*->fun_, *iters...);}, inner_.current_);
Remarks: Let Is be the pack 0, 1, …, (sizeof...(Views) - 1).
The exception specification is equivalent to:noexcept(invoke(**parent_*->fun_, *std::get(inner_.current_)...)).
constexpr iterator& operator++();
Effects: Equivalent to:++inner_;return *this;
constexpr void operator++(int);
Effects: Equivalent to: ++*this.
constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto tmp = *this;++*this;return tmp;
constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:--inner_;return *this;
constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto tmp = *this;--*this;return tmp;
constexpr iterator& operator+=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:inner_ += x;return *this;
constexpr iterator& operator-=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:inner_ -= x;return *this;
constexpr decltype(auto) operator[](difference_type n) const requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:return apply([&]<class... Is>(const Is&... iters) -> decltype(auto) {return invoke(**parent_*->fun_, iters[iter_difference_t(n)]...);}, inner_.current_);
friend constexpr bool operator==(const iterator& x, const iterator& y) requires [equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_comparable [concept.equalitycomparable]")<ziperator<Const>>; friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Let op be the operator.
Effects: Equivalent to:return x.inner_ op y.inner_;
friend constexpr iterator operator+(const iterator& i, difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>; friend constexpr iterator operator+(difference_type n, const iterator& i) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:return iterator(*i.parent_, i.inner_ + n);
friend constexpr iterator operator-(const iterator& i, difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:return iterator(*i.parent_, i.inner_ - n);
friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<ziperator<Const>, ziperator<Const>>;
Effects: Equivalent to:return x.inner_ - y.inner_;
25.7.26.4 Class template zip_transform_view::sentinel [range.zip.transform.sentinel]
namespace std::ranges {template<move_constructible F, input_range... Views>requires (view && ...) && (sizeof...(Views) > 0) && is_object_v &®ular_invocable<F&, range_reference_t...> &&can-reference<invoke_result_t<F&, range_reference_t...>>templateclass zip_transform_view<F, Views...>::sentinel {zentinel inner_; // exposition onlyconstexpr explicit sentinel(zentinel inner); // exposition onlypublic:sentinel() = default; constexpr sentinel(sentinel i)requires Const && convertible_to<zentinel, zentinel>; templaterequires sentinel_for<zentinel, ziperator>friend constexpr bool operator==(const iterator& x, const sentinel& y); templaterequires sized_sentinel_for<zentinel, ziperator>friend constexpr range_difference_t<maybe-const<OtherConst, InnerView>>operator-(const iterator& x, const sentinel& y); templaterequires sized_sentinel_for<zentinel, ziperator>friend constexpr range_difference_t<maybe-const<OtherConst, InnerView>>operator-(const sentinel& x, const iterator& y); };}
constexpr explicit sentinel(zentinel<Const> inner);
Effects: Initializes inner_ with inner.
constexpr sentinel(sentinel<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<zentinel<false>, zentinel<Const>>;
Effects: Initializes inner_ with std::move(i.inner_).
template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7 Concept sentinel_for [iterator.concept.sentinel]")<zentinel<Const>, ziperator<OtherConst>> friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
Effects: Equivalent to: return x.inner_ == y.inner_;
template<bool OtherConst> requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<zentinel<Const>, ziperator<OtherConst>> friend constexpr range_difference_t<maybe-const<OtherConst, InnerView>> operator-(const iterator<OtherConst>& x, const sentinel& y); template<bool OtherConst> requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<zentinel<Const>, ziperator<OtherConst>> friend constexpr range_difference_t<maybe-const<OtherConst, InnerView>> operator-(const sentinel& x, const iterator<OtherConst>& y);
Effects: Equivalent to: return x.inner_ - y.inner_;
25.7.27 Adjacent view [range.adjacent]
25.7.27.1 Overview [range.adjacent.overview]
adjacent_view takes a view and produces a view whose Mth element is a tuple of references to the Mth through (M+Nâ1)th elements of the original view.
If the original view has fewer than N elements, the resulting view is empty.
The name views::adjacent denotes a range adaptor object ([range.adaptor.object]).
Given a subexpression E and a constant expression N, the expression views::adjacent(E) is expression-equivalent to
((void)E, auto(views::empty<tuple<>>)) if N is equal to 0 anddecltype((E)) models forward_range,
otherwise, adjacent_view<views::all_t<decltype((E))>, N>(E).
[Example 1: vector v = {1, 2, 3, 4};
for (auto i : v | views::adjacent<2>) { cout << "(" << std::get<0>(i) << ", " << std::get<1>(i) << ") "; // prints (1, 2) (2, 3) (3, 4)} â end example]
Define REPEAT(T, N) as a pack of N types, each of which denotes the same type as T.
25.7.27.2 Class template adjacent_view [range.adjacent.view]
namespace std::ranges {template<forward_range V, size_t N>requires view && (N > 0)class adjacent_view : public view_interface<adjacent_view<V, N>> { V base_ = V(); // exposition only// [range.adjacent.iterator], class template adjacent_view::iteratortemplate class iterator; // exposition only// [range.adjacent.sentinel], class template adjacent_view::sentineltemplate class sentinel; // exposition onlystruct as-sentinel{}; // exposition onlypublic: adjacent_view() requires default_initializable = default; constexpr explicit adjacent_view(V base); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr auto begin() requires () {return iterator(ranges::begin(base_), ranges::end(base_)); }constexpr auto begin() const requires range {return iterator(ranges::begin(base_), ranges::end(base_)); }constexpr auto end() requires (
) {if constexpr (common_range) {return iterator(as-sentinel{}, ranges::begin(base_), ranges::end(base_)); } else {return sentinel(ranges::end(base_)); }}constexpr auto end() const requires range {if constexpr (common_range) {return iterator(as-sentinel{}, ranges::begin(base_), ranges::end(base_)); } else {return sentinel(ranges::end(base_)); }}constexpr auto size() requires sized_range; constexpr auto size() const requires sized_range; constexpr auto reserve_hint() requires approximately_sized_range; constexpr auto reserve_hint() const requires approximately_sized_range; };}
constexpr explicit adjacent_view(V base);
Effects: Initializes base_ with std::move(base).
constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<V>; constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<const V>;
Effects: Equivalent to:using ST = decltype(ranges::size(base_));using CT = common_type_t<ST, size_t>;auto sz = static_cast(ranges::size(base_)); sz -= std::min(sz, N - 1);return static_cast(sz);
constexpr auto reserve_hint() requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3 Approximately sized ranges [range.approximately.sized]")<V>; constexpr auto reserve_hint() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3 Approximately sized ranges [range.approximately.sized]")<const V>;
Effects: Equivalent to:using DT = range_difference_t<decltype((base_))>;using CT = common_type_t<DT, size_t>;auto sz = static_cast(ranges::reserve_hint(base_)); sz -= std::min(sz, N - 1);return to-unsigned-like(sz);
25.7.27.3 Class template adjacent_view::iterator [range.adjacent.iterator]
namespace std::ranges {template<forward_range V, size_t N>requires view && (N > 0)templateclass adjacent_view<V, N>::iterator {using Base = maybe-const<Const, V>; // exposition only array<iterator_t<Base>, N> current_ = array<iterator_t<Base>, N>(); // exposition onlyconstexpr iterator(iterator_t<Base> first, sentinel_t<Base> last); // exposition onlyconstexpr iterator(as-sentinel, iterator_t<Base> first, iterator_t<Base> last); // exposition onlypublic:using iterator_category = input_iterator_tag; using iterator_concept = see below; using value_type = tuple<REPEAT(range_value_t<Base>, N)...>; using difference_type = range_difference_t<Base>; iterator() = default; constexpr iterator(iterator i)requires Const && convertible_to<iterator_t, iterator_t<Base>>; constexpr auto operator*() const; constexpr iterator& operator++(); constexpr iterator operator++(int); 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 auto operator[](difference_type n) constrequires random_access_range<Base>; friend constexpr bool operator==(const iterator& x, const iterator& y); 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+(const iterator& i, difference_type n)requires random_access_range<Base>; friend constexpr iterator operator+(difference_type n, const iterator& i)requires random_access_range<Base>; friend constexpr iterator operator-(const iterator& i, difference_type n)requires random_access_range<Base>; friend constexpr difference_type operator-(const iterator& x, const iterator& y)requires sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>; friend constexpr auto iter_move(const iterator& i) noexcept(see below); friend constexpr void iter_swap(const iterator& l, const iterator& r) noexcept(see below)requires indirectly_swappable<iterator_t<Base>>; };}
iterator::iterator_concept is defined as follows:
-
If Base models random_access_range, then iterator_concept denotes random_access_iterator_tag.
-
Otherwise, if Base models bidirectional_range, then iterator_concept denotes bidirectional_iterator_tag.
-
Otherwise, iterator_concept denotes forward_iterator_tag.
If the invocation of any non-const member function of iterator exits via an exception, the iterator acquires a singular value.
constexpr iterator(iterator_t<Base> first, sentinel_t<Base> last);
Postconditions: current_[0] == first is true, and for every integer 1â¤i<N,current_[i] == ranges::next(current_[i-1], 1, last) is true.
constexpr iterator(as-sentinel, iterator_t<Base> first, iterator_t<Base> last);
Postconditions: If Base does not model bidirectional_range, each element of current_ is equal to last.
Otherwise, current_[N-1] == last is true, and for every integer 0â¤i<(Nâ1),current_[i] == ranges::prev(current_[i+1], 1, first) is true.
constexpr iterator(iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<V>, iterator_t<Base>>;
Effects: Initializes each element of current_ with the corresponding element of i.current_ as an xvalue.
constexpr auto operator*() const;
Effects: Equivalent to:return tuple-transform([](auto& i) -> decltype(auto) { return *i; }, current_);
constexpr iterator& operator++();
Preconditions: current_.back() is incrementable.
Postconditions: Each element of current_ is equal to ranges::next(i), where i is the value of that element before the call.
Returns: *this.
constexpr iterator operator++(int);
Effects: Equivalent to:auto tmp = *this;++*this;return tmp;
constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Preconditions: current_.front() is decrementable.
Postconditions: Each element of current_ is equal to ranges::prev(i), where i is the value of that element before the call.
Returns: *this.
constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto tmp = *this;--*this;return tmp;
constexpr iterator& operator+=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Preconditions: current_.back() + x has well-defined behavior.
Postconditions: Each element of current_ is equal to i + x, where i is the value of that element before the call.
Returns: *this.
constexpr iterator& operator-=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Preconditions: current_.front() - x has well-defined behavior.
Postconditions: Each element of current_ is equal to i - x, where i is the value of that element before the call.
Returns: *this.
constexpr auto operator[](difference_type n) const requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:return tuple-transform([&](auto& i) -> decltype(auto) { return i[n]; }, current_);
friend constexpr bool operator==(const iterator& x, const iterator& y);
Returns: x.current_.back() == y.current_.back().
friend constexpr bool operator<(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Returns: x.current_.back() < y.current_.back().
friend constexpr bool operator>(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return y < x;
friend constexpr bool operator<=(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return !(y < x);
friend constexpr bool operator>=(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return !(x < y);
friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base> && [three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4 Concept three_way_comparable [cmp.concept]")<iterator_t<Base>>;
Returns: x.current_.back() <=> y.current_.back().
friend constexpr iterator operator+(const iterator& i, difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>; friend constexpr iterator operator+(difference_type n, const iterator& i) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto r = i; r += n;return r;
friend constexpr iterator operator-(const iterator& i, difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto r = i; r -= n;return r;
friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<iterator_t<Base>, iterator_t<Base>>;
Effects: Equivalent to:return x.current_.back() - y.current_.back();
friend constexpr auto iter_move(const iterator& i) noexcept(see below);
Effects: Equivalent to:return tuple-transform(ranges::iter_move, i.current_);
Remarks: The exception specification is equivalent to:noexcept(ranges::iter_move(declval<const iterator_t<Base>&>())) && is_nothrow_move_constructible_v<range_rvalue_reference_t<Base>>
friend constexpr void iter_swap(const iterator& l, const iterator& r) noexcept(see below) requires [indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept indirectly_swappable [alg.req.ind.swap]")<iterator_t<Base>>;
Preconditions: None of the iterators in l.current_ is equal to an iterator in r.current_.
Effects: For every integer 0â¤i<N, performsranges::iter_swap(l.current_[i], r.current_[i]).
Remarks: The exception specification is equivalent to:noexcept(ranges::iter_swap(declval<iterator_t<Base>>(), declval<iterator_t<Base>>()))
25.7.27.4 Class template adjacent_view::sentinel [range.adjacent.sentinel]
namespace std::ranges {template<forward_range V, size_t N>requires view && (N > 0)templateclass adjacent_view<V, N>::sentinel {using Base = maybe-const<Const, V>; // exposition only sentinel_t<Base> end_ = sentinel_t<Base>(); // exposition onlyconstexpr explicit sentinel(sentinel_t<Base> end); // exposition onlypublic:sentinel() = default; constexpr sentinel(sentinel i)requires Const && convertible_to<sentinel_t, sentinel_t<Base>>; templaterequires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>friend constexpr bool operator==(const iterator& x, const sentinel& y); templaterequires sized_sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>friend constexpr range_difference_t<maybe-const<OtherConst, V>>operator-(const iterator& x, const sentinel& y); templaterequires sized_sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>friend constexpr range_difference_t<maybe-const<OtherConst, V>>operator-(const sentinel& y, const iterator& x); };}
constexpr explicit sentinel(sentinel_t<Base> end);
Effects: Initializes end_ with end.
constexpr sentinel(sentinel<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;
Effects: Initializes end_ with std::move(i.end_).
template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7 Concept sentinel_for [iterator.concept.sentinel]")<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
Effects: Equivalent to: return x.current_.back() == y.end_;
template<bool OtherConst> requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr range_difference_t<maybe-const<OtherConst, V>> operator-(const iterator<OtherConst>& x, const sentinel& y);
Effects: Equivalent to: return x.current_.back() - y.end_;
template<bool OtherConst> requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr range_difference_t<maybe-const<OtherConst, V>> operator-(const sentinel& y, const iterator<OtherConst>& x);
Effects: Equivalent to: return y.end_ - x.current_.back();
25.7.28 Adjacent transform view [range.adjacent.transform]
25.7.28.1 Overview [range.adjacent.transform.overview]
adjacent_transform_view takes an invocable object and a view and produces a view whose Mth element is the result of applying the invocable object to the Mth through (M+Nâ1)th elements of the original view.
If the original view has fewer than N elements, the resulting view is empty.
The name views::adjacent_transform denotes a range adaptor object ([range.adaptor.object]).
Given subexpressions E and F and a constant expression N:
-
If N is equal to 0 anddecltype((E)) models forward_range,views::adjacent_transform(E, F) is expression-equivalent to((void)E, views::zip_transform(F)), except that the evaluations of E and F are indeterminately sequenced.
-
Otherwise, the expression views::adjacent_transform(E, F) is expression-equivalent toadjacent_transform_view<views::all_t<decltype((E))>, decay_t<decltype((F))>, N>(E, F).
[Example 1: vector v = {1, 2, 3, 4};
for (auto i : v | views::adjacent_transform<2>(std::multiplies())) { cout << i << ' '; // prints 2 6 12} â end example]
25.7.28.2 Class template adjacent_transform_view [range.adjacent.transform.view]
namespace std::ranges {template<forward_range V, move_constructible F, size_t N>requires view && (N > 0) && is_object_v &®ular_invocable<F&, REPEAT(range_reference_t, N)...> &&can-reference<invoke_result_t<F&, REPEAT(range_reference_t, N)...>>class adjacent_transform_view : public view_interface<adjacent_transform_view<V, F, N>> {movable-box fun_; // exposition only adjacent_view<V, N> inner_; // exposition onlyusing InnerView = adjacent_view<V, N>; // exposition onlytemplateusing inner-iterator = iterator_t<maybe-const<Const, InnerView>>; // exposition onlytemplateusing inner-sentinel = sentinel_t<maybe-const<Const, InnerView>>; // exposition only// [range.adjacent.transform.iterator], class template adjacent_transform_view::iteratortemplate class iterator; // exposition only// [range.adjacent.transform.sentinel], class template adjacent_transform_view::sentineltemplate class sentinel; // exposition onlypublic: adjacent_transform_view() = default; constexpr explicit adjacent_transform_view(V base, F fun); constexpr V base() const & requires copy_constructible { return inner_.base(); }constexpr V base() && { return std::move(inner_).base(); }constexpr auto begin() {return iterator(*this, inner_.begin()); }constexpr auto begin() constrequires range<const InnerView> &®ular_invocable<const F&, REPEAT(range_reference_t, N)...> {return iterator(*this, inner_.begin()); }constexpr auto end() {if constexpr (common_range<InnerView>) {return iterator(*this, inner_.end()); } else {return sentinel(inner_.end()); }}constexpr auto end() constrequires range<const InnerView> &®ular_invocable<const F&, REPEAT(range_reference_t, N)...> {if constexpr (common_range<const InnerView>) {return iterator(*this, inner_.end()); } else {return sentinel(inner_.end()); }}constexpr auto size() requires sized_range<InnerView> {return inner_.size(); }constexpr auto size() const requires sized_range<const InnerView> {return inner_.size(); }constexpr auto reserve_hint() requires approximately_sized_range<InnerView> {return inner_.reserve_hint(); }constexpr auto reserve_hint() const requires approximately_sized_range<const InnerView> {return inner_.reserve_hint(); }};}
constexpr explicit adjacent_transform_view(V base, F fun);
Effects: Initializes fun_ with std::move(fun) andinner_ with std::move(base).
25.7.28.3 Class template adjacent_transform_view::iterator [range.adjacent.transform.iterator]
namespace std::ranges {template<forward_range V, move_constructible F, size_t N>requires view && (N > 0) && is_object_v &®ular_invocable<F&, REPEAT(range_reference_t, N)...> &&can-reference<invoke_result_t<F&, REPEAT(range_reference_t, N)...>>templateclass adjacent_transform_view<V, F, N>::iterator {using Parent = maybe-const<Const, adjacent_transform_view>; // exposition onlyusing Base = maybe-const<Const, V>; // exposition onlyParent parent_ = nullptr; // exposition only**inner-iterator inner_; // exposition onlyconstexpr iterator(Parent& parent, inner-iterator inner); // exposition onlypublic:using iterator_category = see below; using iterator_concept = typename inner-iterator::iterator_concept; using value_type = remove_cvref_t<invoke_result_t<maybe-const<Const, F>&, REPEAT(range_reference_t<Base>, N)...>>; using difference_type = range_difference_t<Base>; iterator() = default; constexpr iterator(iterator i)requires Const && convertible_to<inner-iterator, inner-iterator>; constexpr decltype(auto) operator() const noexcept(see below); constexpr iterator& operator++(); constexpr iterator operator++(int); 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) constrequires random_access_range<Base>; friend constexpr bool operator==(const iterator& x, const iterator& y); 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<inner-iterator>; friend constexpr iterator operator+(const iterator& i, difference_type n)requires random_access_range<Base>; friend constexpr iterator operator+(difference_type n, const iterator& i)requires random_access_range<Base>; friend constexpr iterator operator-(const iterator& i, difference_type n)requires random_access_range<Base>; friend constexpr difference_type operator-(const iterator& x, const iterator& y)requires sized_sentinel_for<inner-iterator, inner-iterator>; };}
The member typedef-name iterator::iterator_category is defined as follows:
-
If invoke_result_t<maybe-const<Const, F>&,REPEAT(range_reference_t<Base>, N)...> is not a reference,iterator_category denotes input_iterator_tag.
-
Otherwise, let C denote the typeiterator_traits<iterator_t<Base>>::iterator_category.
-
If derived_from<C, random_access_iterator_tag> is true,iterator_category denotes random_access_iterator_tag.
-
Otherwise, if derived_from<C, bidirectional_iterator_tag> is true,iterator_category denotes bidirectional_iterator_tag.
-
Otherwise, if derived_from<C, forward_iterator_tag> is true,iterator_category denotes forward_iterator_tag.
-
Otherwise, iterator_category denotes input_iterator_tag.
-
constexpr iterator(Parent& parent, inner-iterator<Const> inner);
Effects: Initializes parent_ with addressof(parent) andinner_ with std::move(inner).
constexpr iterator(iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<inner-iterator<false>, inner-iterator<Const>>;
Effects: Initializes parent_ with i.parent_ andinner_ with std::move(i.inner_).
constexpr decltype(auto) operator*() const noexcept(see below);
Effects: Equivalent to:return apply([&](const auto&... iters) -> decltype(auto) {return invoke(**parent_*->fun_, *iters...);}, inner_.current_);
Remarks: Let Is be the pack 0, 1, …, (N - 1).
The exception specification is equivalent to:noexcept(invoke(**parent_*->fun_, *std::get(inner_.current_)...))
constexpr iterator& operator++();
Effects: Equivalent to:++inner_;return *this;
constexpr iterator operator++(int);
Effects: Equivalent to:auto tmp = *this;++*this;return tmp;
constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:--inner_;return *this;
constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto tmp = *this;--*this;return tmp;
constexpr iterator& operator+=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:inner_ += x;return *this;
constexpr iterator& operator-=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:inner_ -= x;return *this;
constexpr decltype(auto) operator[](difference_type n) const requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:return apply([&](const auto&... iters) -> decltype(auto) {return invoke(**parent_*->fun_, iters[n]...);}, inner_.current_);
friend constexpr bool operator==(const iterator& x, const iterator& y); friend constexpr bool operator<(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>; friend constexpr bool operator>(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>; friend constexpr bool operator<=(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>; friend constexpr bool operator>=(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>; friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base> && [three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4 Concept three_way_comparable [cmp.concept]")<inner-iterator<Const>>;
Let op be the operator.
Effects: Equivalent to: return x.inner_ op y.inner_;
friend constexpr iterator operator+(const iterator& i, difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>; friend constexpr iterator operator+(difference_type n, const iterator& i) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return iterator(*i.parent_, i.inner_ + n);
friend constexpr iterator operator-(const iterator& i, difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return iterator(*i.parent_, i.inner_ - n);
friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<inner-iterator<Const>, inner-iterator<Const>>;
Effects: Equivalent to: return x.inner_ - y.inner_;
25.7.28.4 Class template adjacent_transform_view::sentinel [range.adjacent.transform.sentinel]
namespace std::ranges {template<forward_range V, move_constructible F, size_t N>requires view && (N > 0) && is_object_v &®ular_invocable<F&, REPEAT(range_reference_t, N)...> &&can-reference<invoke_result_t<F&, REPEAT(range_reference_t, N)...>>templateclass adjacent_transform_view<V, F, N>::sentinel {inner-sentinel inner_; // exposition onlyconstexpr explicit sentinel(inner-sentinel inner); // exposition onlypublic:sentinel() = default; constexpr sentinel(sentinel i)requires Const && convertible_to<inner-sentinel, inner-sentinel>; templaterequires sentinel_for<inner-sentinel, inner-iterator>friend constexpr bool operator==(const iterator& x, const sentinel& y); templaterequires sized_sentinel_for<inner-sentinel, inner-iterator>friend constexpr range_difference_t<maybe-const<OtherConst, InnerView>>operator-(const iterator& x, const sentinel& y); templaterequires sized_sentinel_for<inner-sentinel, inner-iterator>friend constexpr range_difference_t<maybe-const<OtherConst, InnerView>>operator-(const sentinel& x, const iterator& y); };}
constexpr explicit sentinel(inner-sentinel<Const> inner);
Effects: Initializes inner_ with inner.
constexpr sentinel(sentinel<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<inner-sentinel<false>, inner-sentinel<Const>>;
Effects: Initializes inner_ with std::move(i.inner_).
template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7 Concept sentinel_for [iterator.concept.sentinel]")<inner-sentinel<Const>, inner-iterator<OtherConst>> friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
Effects: Equivalent to: return x.inner_ == y.inner_;
`template requires sized_sentinel_for<inner-sentinel, inner-iterator> friend constexpr range_difference_t<maybe-const<OtherConst, InnerView>> operator-(const iterator& x, const sentinel& y);
template requires sized_sentinel_for<inner-sentinel, inner-iterator> friend constexpr range_difference_t<maybe-const<OtherConst, InnerView>> operator-(const sentinel& x, const iterator& y); `
Effects: Equivalent to: return x.inner_ - y.inner_;
25.7.29 Chunk view [range.chunk]
25.7.29.1 Overview [range.chunk.overview]
chunk_view takes a view and a number N and produces a range of views that are N-sized non-overlapping successive chunks of the elements of the original view, in order.
The last view in the range can have fewer than N elements.
The name views::chunk denotes a range adaptor object ([range.adaptor.object]).
Given subexpressions E and N, the expression views::chunk(E, N) is expression-equivalent tochunk_view(E, N).
[Example 1: vector v = {1, 2, 3, 4, 5};
for (auto r : v | views::chunk(2)) { cout << '['; auto sep = ""; for (auto i : r) { cout << sep << i; sep = ", "; } cout << "] ";}// The above prints [1, 2] [3, 4] [5] â end example]
25.7.29.2 Class template chunk_view for input ranges [range.chunk.view.input]
namespace std::ranges {templateconstexpr I div-ceil(I num, I denom) { // exposition only I r = num / denom; if (num % denom)++r; return r; }template<view V>requires input_rangeclass chunk_view : public view_interface<chunk_view> { V base_; // exposition only range_difference_t n_; // exposition only range_difference_t remainder_ = 0; // exposition only**non-propagating-cache<iterator_t> current_; // exposition only// [range.chunk.outer.iter], class chunk_view::outer-iteratorclass outer-iterator; // exposition only// [range.chunk.inner.iter], class chunk_view::inner-iteratorclass inner-iterator; // exposition onlypublic:constexpr explicit chunk_view(V base, range_difference_t n); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr outer-iterator begin(); constexpr default_sentinel_t end() const noexcept; constexpr auto size() requires sized_range; constexpr auto size() const requires sized_range; constexpr auto reserve_hint() requires approximately_sized_range; constexpr auto reserve_hint() const requires approximately_sized_range; }; template chunk_view(R&&, range_difference_t) -> chunk_view<views::all_t>;}
constexpr explicit chunk_view(V base, range_difference_t<V> n);
Preconditions: n > 0 is true.
Effects: Initializes base_ with std::move(base) andn_ with n.
constexpr outer-iterator begin();
Effects: Equivalent to:current_ = ranges::begin(base_);remainder_ = n_;return outer-iterator(*this);
constexpr default_sentinel_t end() const noexcept;
Returns: default_sentinel.
constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<V>; constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<const V>;
Effects: Equivalent to:return to-unsigned-like(div-ceil(ranges::distance(base_), n_));
constexpr auto reserve_hint() requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3 Approximately sized ranges [range.approximately.sized]")<V>; constexpr auto reserve_hint() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3 Approximately sized ranges [range.approximately.sized]")<const V>;
Effects: Equivalent to:auto s = static_cast<range_difference_t<decltype((base_))>>(ranges::reserve_hint(base_));return to-unsigned-like(div-ceil(s, n_));
25.7.29.3 Class chunk_view::outer-iterator [range.chunk.outer.iter]
namespace std::ranges {template<view V>requires input_rangeclass chunk_view::outer-iterator { chunk_view* parent_; // exposition onlyconstexpr explicit outer-iterator(chunk_view& parent); // exposition onlypublic:using iterator_concept = input_iterator_tag; using difference_type = range_difference_t; // [range.chunk.outer.value], class chunk_view::outer-iterator::value_typestruct value_type; outer-iterator(outer-iterator&&) = default; outer-iterator& operator=(outer-iterator&&) = default; constexpr value_type operator*() const; constexpr outer-iterator& operator++(); constexpr void operator++(int); friend constexpr bool operator==(const outer-iterator& x, default_sentinel_t); friend constexpr difference_type operator-(default_sentinel_t y, const outer-iterator& x)requires sized_sentinel_for<sentinel_t, iterator_t>; friend constexpr difference_type operator-(const outer-iterator& x, default_sentinel_t y)requires sized_sentinel_for<sentinel_t, iterator_t>; };}
constexpr explicit outer-iterator(chunk_view& parent);
Effects: Initializes parent_ with addressof(parent).
constexpr value_type operator*() const;
Preconditions: *this == default_sentinel is false.
Returns: value_type(**parent_*).
constexpr outer-iterator& operator++();
Preconditions: *this == default_sentinel is false.
Effects: Equivalent to:ranges::advance(**parent_*->current_, parent_->remainder_, ranges::end(parent_->base_));parent_->remainder_ = parent_->n_;return *this;
constexpr void operator++(int);
Effects: Equivalent to ++*this.
friend constexpr bool operator==(const outer-iterator& x, default_sentinel_t);
Effects: Equivalent to:return *x.parent_->current_ == ranges::end(x.parent_->base_) && x.parent_->remainder_ != 0;
friend constexpr difference_type operator-(default_sentinel_t y, const outer-iterator& x) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;
Effects: Equivalent to:const auto dist = ranges::end(x.parent_->base_) - *x.parent_->current_;if (dist < x.parent_->remainder_) {return dist == 0 ? 0 : 1;}return div-ceil(dist - x.parent_->remainder_, x.parent_->n_) + 1;
friend constexpr difference_type operator-(const outer-iterator& x, default_sentinel_t y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;
Effects: Equivalent to: return -(y - x);
25.7.29.4 Class chunk_view::outer-iterator::value_type [range.chunk.outer.value]
namespace std::ranges {template<view V>requires input_rangestruct chunk_view::outer-iterator::value_type : view_interface<value_type> {private: chunk_view* parent_; // exposition onlyconstexpr explicit value_type(chunk_view& parent); // exposition onlypublic:constexpr inner-iterator begin() const noexcept; constexpr default_sentinel_t end() const noexcept; constexpr auto size() constrequires sized_sentinel_for<sentinel_t, iterator_t>; constexpr auto reserve_hint() const noexcept; };}
constexpr explicit value_type(chunk_view& parent);
Effects: Initializes parent_ with addressof(parent).
constexpr inner-iterator begin() const noexcept;
Returns: inner-iterator(**parent_*).
constexpr default_sentinel_t end() const noexcept;
Returns: default_sentinel.
constexpr auto size() const requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;
Effects: Equivalent to:return to-unsigned-like(ranges::min(parent_->remainder_, ranges::end(parent_->base_) - **parent_*->current_));
constexpr auto reserve_hint() const noexcept;
Effects: Equivalent to:return to-unsigned-like(parent_->remainder_);
25.7.29.5 Class chunk_view::inner-iterator [range.chunk.inner.iter]
namespace std::ranges {template<view V>requires input_rangeclass chunk_view::inner-iterator { chunk_view* parent_; // exposition onlyconstexpr explicit inner-iterator(chunk_view& parent) noexcept; // exposition onlypublic:using iterator_concept = input_iterator_tag; using difference_type = range_difference_t; using value_type = range_value_t; inner-iterator(inner-iterator&&) = default; inner-iterator& operator=(inner-iterator&&) = default; constexpr const iterator_t& base() const &; constexpr range_reference_t operator*() const; constexpr inner-iterator& operator++(); constexpr void operator++(int); friend constexpr bool operator==(const inner-iterator& x, default_sentinel_t); friend constexpr difference_type operator-(default_sentinel_t y, const inner-iterator& x)requires sized_sentinel_for<sentinel_t, iterator_t>; friend constexpr difference_type operator-(const inner-iterator& x, default_sentinel_t y)requires sized_sentinel_for<sentinel_t, iterator_t>; friend constexpr range_rvalue_reference_t iter_move(const inner-iterator& i)noexcept(noexcept(ranges::iter_move(*i.parent_->current_))); friend constexpr void iter_swap(const inner-iterator& x, const inner-iterator& y)noexcept(noexcept(ranges::iter_swap(*x.parent_->current_, *y.parent_->current_)))requires indirectly_swappable<iterator_t>; };}
constexpr explicit inner-iterator(chunk_view& parent) noexcept;
Effects: Initializes parent_ with addressof(parent).
constexpr const iterator_t<V>& base() const &;
Effects: Equivalent to: return **parent_*->current_;
constexpr range_reference_t<V> operator*() const;
Preconditions: *this == default_sentinel is false.
Effects: Equivalent to: return **parent_->current_;
constexpr inner-iterator& operator++();
Preconditions: *this == default_sentinel is false.
Effects: Equivalent to:++**parent_->current_;if (**parent_->current_ == ranges::end(parent_->base_))parent_->remainder_ = 0;else--parent_->remainder_;return *this;
constexpr void operator++(int);
Effects: Equivalent to ++*this.
friend constexpr bool operator==(const inner-iterator& x, default_sentinel_t);
Returns: x.parent_->remainder_ == 0.
friend constexpr difference_type operator-(default_sentinel_t y, const inner-iterator& x) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;
Effects: Equivalent to:return ranges::min(x.parent_->remainder_, ranges::end(x.parent_->base_) - *x.parent_->current_);
friend constexpr difference_type operator-(const inner-iterator& x, default_sentinel_t y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;
Effects: Equivalent to: return -(y - x);
friend constexpr range_rvalue_reference_t<V> iter_move(const inner-iterator& i) noexcept(noexcept(ranges::iter_move(*i.parent_->current_)));
Effects: Equivalent to: return ranges::iter_move(*i.parent_->current_);
friend constexpr void iter_swap(const inner-iterator& x, const inner-iterator& y) noexcept(noexcept(ranges::iter_swap(*x.parent_->current_, *y.parent_->current_))) requires [indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept indirectly_swappable [alg.req.ind.swap]")<iterator_t<V>>;
Effects: Equivalent to: ranges::iter_swap(*x.parent_->current_, *y.parent_->current_);
25.7.29.6 Class template chunk_view for forward ranges [range.chunk.view.fwd]
namespace std::ranges {template<view V>requires forward_rangeclass chunk_view : public view_interface<chunk_view> { V base_; // exposition only range_difference_t n_; // exposition only// [range.chunk.fwd.iter], class template chunk_view::iteratortemplate class iterator; // exposition onlypublic:constexpr explicit chunk_view(V base, range_difference_t n); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr auto begin() requires () {return iterator(this, ranges::begin(base_)); }constexpr auto begin() const requires forward_range {return iterator(this, ranges::begin(base_)); }constexpr auto end() requires (
) {if constexpr (common_range && sized_range) {auto missing = (n_ - ranges::distance(base_) % n_) % n_; return iterator(this, ranges::end(base_), missing); } else if constexpr (common_range &&
) {return iterator(this, ranges::end(base_)); } else {return default_sentinel; }}constexpr auto end() const requires forward_range {if constexpr (common_range && sized_range) {auto missing = (n_ - ranges::distance(base_) % n_) % n_; return iterator(this, ranges::end(base_), missing); } else if constexpr (common_range &&
) {return iterator(this, ranges::end(base_)); } else {return default_sentinel; }}constexpr auto size() requires sized_range; constexpr auto size() const requires sized_range; constexpr auto reserve_hint() requires approximately_sized_range; constexpr auto reserve_hint() const requires approximately_sized_range; };}
constexpr explicit chunk_view(V base, range_difference_t<V> n);
Preconditions: n > 0 is true.
Effects: Initializes base_ with std::move(base) andn_ with n.
constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<V>; constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<const V>;
Effects: Equivalent to:return to-unsigned-like(div-ceil(ranges::distance(base_), n_));
constexpr auto reserve_hint() requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3 Approximately sized ranges [range.approximately.sized]")<V>; constexpr auto reserve_hint() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3 Approximately sized ranges [range.approximately.sized]")<const V>;
Effects: Equivalent to:auto s = static_cast<range_difference_t<decltype((base_))>>(ranges::reserve_hint(base_));return to-unsigned-like(div-ceil(s, n_));
25.7.29.7 Class template chunk_view::iterator for forward ranges [range.chunk.fwd.iter]
namespace std::ranges {template<view V>requires forward_rangetemplateclass chunk_view::iterator {using Parent = maybe-const<Const, chunk_view>; // exposition onlyusing Base = maybe-const<Const, V>; // exposition only iterator_t<Base> current_ = iterator_t<Base>(); // exposition only sentinel_t<Base> end_ = sentinel_t<Base>(); // exposition only range_difference_t<Base> n_ = 0; // exposition only range_difference_t<Base> missing_ = 0; // exposition onlyconstexpr iterator(Parent* parent, iterator_t<Base> current, // exposition only range_difference_t<Base> missing = 0); public:using iterator_category = input_iterator_tag; using iterator_concept = see below; using value_type = decltype(views::take(subrange(current_, end_), n_)); using difference_type = range_difference_t<Base>; iterator() = default; constexpr iterator(iterator i)requires Const && convertible_to<iterator_t, iterator_t<Base>>&& convertible_to<sentinel_t, sentinel_t<Base>>; constexpr iterator_t<Base> base() const; constexpr value_type operator*() const; constexpr iterator& operator++(); constexpr iterator operator++(int); 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 value_type operator[](difference_type n) constrequires random_access_range<Base>; friend constexpr bool operator==(const iterator& x, const iterator& y); friend constexpr bool operator==(const iterator& x, default_sentinel_t); 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+(const iterator& i, difference_type n)requires random_access_range<Base>; friend constexpr iterator operator+(difference_type n, const iterator& i)requires random_access_range<Base>; friend constexpr iterator operator-(const iterator& i, difference_type n)requires random_access_range<Base>; friend constexpr difference_type operator-(const iterator& x, const iterator& y)requires sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>; friend constexpr difference_type operator-(default_sentinel_t y, const iterator& x)requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>; friend constexpr difference_type operator-(const iterator& x, default_sentinel_t y)requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>; };}
iterator::iterator_concept is defined as follows:
-
If Base models random_access_range, then iterator_concept denotes random_access_iterator_tag.
-
Otherwise, if Base models bidirectional_range, then iterator_concept denotes bidirectional_iterator_tag.
-
Otherwise, iterator_concept denotes forward_iterator_tag.
constexpr iterator(Parent* parent, iterator_t<Base> current, range_difference_t<Base> missing = 0);
Effects: Initializes current_ with current,end_ with ranges::end(parent->base_),n_ with parent->n_, andmissing_ with missing.
constexpr iterator(iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<V>, iterator_t<Base>> && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;
Effects: Initializes current_ with std::move(i.current_),end_ with std::move(i.end_),n_ with i.n_, andmissing_ with i.missing_.
constexpr iterator_t<Base> base() const;
Returns: current_.
constexpr value_type operator*() const;
Preconditions: current_ != end_ is true.
Returns: views::take(subrange(current_, end_), n_).
constexpr iterator& operator++();
Preconditions: current_ != end_ is true.
Effects: Equivalent to:missing_ = ranges::advance(current_, n_, end_);return *this;
constexpr iterator operator++(int);
Effects: Equivalent to:auto tmp = *this;++*this;return tmp;
constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:ranges::advance(current_, missing_ - n_);missing_ = 0;return *this;
constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto tmp = *this;--*this;return tmp;
constexpr iterator& operator+=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Preconditions: If x is positive,ranges::distance(current_, end_) > n_ * (x - 1) is true.
[Note 1:
If x is negative, the Effects paragraph implies a precondition.
â end note]
Effects: Equivalent to:if (x > 0) { ranges::advance(current_, n_ * (x - 1)); missing_ = ranges::advance(current_, n_, end_);} else if (x < 0) { ranges::advance(current_, n_ * x + missing_); missing_ = 0;}return *this;
constexpr iterator& operator-=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return *this += -x;
constexpr value_type operator[](difference_type n) const requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Returns: *(*this + n).
friend constexpr bool operator==(const iterator& x, const iterator& y);
Returns: x.current_ == y.current_.
friend constexpr bool operator==(const iterator& x, default_sentinel_t);
Returns: x.current_ == x.end_.
friend constexpr bool operator<(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Returns: x.current_ < y.current_.
friend constexpr bool operator>(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return y < x;
friend constexpr bool operator<=(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return !(y < x);
friend constexpr bool operator>=(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return !(x < y);
friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base> && [three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4 Concept three_way_comparable [cmp.concept]")<iterator_t<Base>>;
Returns: x.current_ <=> y.current_.
friend constexpr iterator operator+(const iterator& i, difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>; friend constexpr iterator operator+(difference_type n, const iterator& i) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto r = i; r += n;return r;
friend constexpr iterator operator-(const iterator& i, difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto r = i; r -= n;return r;
friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<iterator_t<Base>, iterator_t<Base>>;
Returns: (x.current_ - y.current_ + x.missing_ - y.missing_) / x.n_.
friend constexpr difference_type operator-(default_sentinel_t y, const iterator& x) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<Base>>;
Returns: div-ceil(x.end_ - x.current_, x.n_).
friend constexpr difference_type operator-(const iterator& x, default_sentinel_t y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<Base>>;
Effects: Equivalent to: return -(y - x);
25.7.30 Slide view [range.slide]
25.7.30.1 Overview [range.slide.overview]
slide_view takes a view and a number N and produces a view whose Mth element is a view over the Mth through(M+Nâ1)th elements of the original view.
If the original view has fewer than N elements, the resulting view is empty.
The name views::slide denotes a range adaptor object ([range.adaptor.object]).
Given subexpressions E and N, the expression views::slide(E, N) is expression-equivalent toslide_view(E, N).
[Example 1: vector v = {1, 2, 3, 4};
for (auto i : v | views::slide(2)) { cout << '[' << i[0] << ", " << i[1] << "] "; // prints [1, 2] [2, 3] [3, 4]} â end example]
25.7.30.2 Class template slide_view [range.slide.view]
namespace std::ranges {templateconcept slide-caches-nothing = random_access_range && sized_range; // exposition onlytemplateconcept slide-caches-last = // exposition only && bidirectional_range && common_range; templateconcept slide-caches-first = // exposition only
&&
; template<forward_range V>requires viewclass slide_view : public view_interface<slide_view> { V base_; // exposition only range_difference_t n_; // exposition only// [range.slide.iterator], class template slide_view::iteratortemplate class iterator; // exposition only// [range.slide.sentinel], class slide_view::sentinelclass sentinel; // exposition onlypublic:constexpr explicit slide_view(V base, range_difference_t n); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr auto begin()requires (!(simple-view && slide-caches-nothing)); constexpr auto begin() const requires slide-caches-nothing; constexpr auto end()requires (!(simple-view && slide-caches-nothing)); constexpr auto end() const requires slide-caches-nothing; constexpr auto size() requires sized_range; constexpr auto size() const requires sized_range; constexpr auto reserve_hintsize() requires approximately_sized_range; constexpr auto reserve_hintsize() const requires approximately_sized_range; }; template slide_view(R&&, range_difference_t) -> slide_view<views::all_t>;}
constexpr explicit slide_view(V base, range_difference_t<V> n);
Preconditions: n > 0 is true.
Effects: Initializes base_ with std::move(base) andn_ with n.
constexpr auto begin() requires (!([simple-view](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]")<V> && [slide-caches-nothing](#concept:slide-caches-nothing "25.7.30.2 Class template slide_view [range.slide.view]")<const V>));
Returns:
If V models slide-caches-first,iterator(ranges::begin(base_), ranges::next(ranges::begin(base_), n_ - 1, ranges::end(base_)), n_)
Otherwise, iterator(ranges::begin(base_), n_).
Remarks: In order to provide the amortized constant-time complexity required by the range concept, this function caches the result within the slide_view for use on subsequent calls when V models slide-caches-first.
constexpr auto begin() const requires [slide-caches-nothing](#concept:slide-caches-nothing "25.7.30.2 Class template slide_view [range.slide.view]")<const V>;
Returns: iterator(ranges::begin(base_), n_).
constexpr auto end() requires (!([simple-view](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]")<V> && [slide-caches-nothing](#concept:slide-caches-nothing "25.7.30.2 Class template slide_view [range.slide.view]")<const V>));
Returns:
If V models slide-caches-nothing,iterator(ranges::begin(base_) + range_difference_t(size()), n_)
Otherwise, if V models slide-caches-last,iterator(ranges::prev(ranges::end(base_), n_ - 1, ranges::begin(base_)), n_)
Otherwise, if V models common_range,iterator(ranges::end(base_), ranges::end(base_), n_)
Otherwise, sentinel(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 slide_view for use on subsequent calls when V models slide-caches-last.
constexpr auto end() const requires [slide-caches-nothing](#concept:slide-caches-nothing "25.7.30.2 Class template slide_view [range.slide.view]")<const V>;
Returns: begin() + range_difference_t(size()).
constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<V>; constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<const V>;
Effects: Equivalent to:auto sz = ranges::distance(base_) - n_ + 1;if (sz < 0) sz = 0;return to-unsigned-like(sz);
constexpr auto reserve_hint() requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3 Approximately sized ranges [range.approximately.sized]")<V>; constexpr auto reserve_hint() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3 Approximately sized ranges [range.approximately.sized]")<const V>;
Effects: Equivalent to:auto sz = static_cast<range_difference_t<decltype((base_))>>(ranges::reserve_hint(base_)) -n_ + 1;if (sz < 0) sz = 0;return to-unsigned-like(sz);
25.7.30.3 Class template slide_view::iterator [range.slide.iterator]
namespace std::ranges {template<forward_range V>requires viewtemplateclass slide_view::iterator {using Base = maybe-const<Const, V>; // exposition only iterator_t<Base> current_ = iterator_t<Base>(); // exposition only iterator_t<Base> last_ele_ = iterator_t<Base>(); // exposition only,// present only if Base models slide-caches-first range_difference_t<Base> n_ = 0; // exposition onlyconstexpr iterator(iterator_t<Base> current, range_difference_t<Base> n) // exposition onlyrequires (<Base>); constexpr iterator(iterator_t<Base> current, iterator_t<Base> last_ele, // exposition only range_difference_t<Base> n)requires slide-caches-first<Base>; public:using iterator_category = input_iterator_tag; using iterator_concept = see below; using value_type = decltype(views::counted(current_, n_)); using difference_type = range_difference_t<Base>; iterator() = default; constexpr iterator(iterator i)requires Const && convertible_to<iterator_t, iterator_t<Base>>; constexpr auto operator*() const; constexpr iterator& operator++(); constexpr iterator operator++(int); 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 auto operator[](difference_type n) constrequires random_access_range<Base>; friend constexpr bool operator==(const iterator& x, const iterator& y); 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+(const iterator& i, difference_type n)requires random_access_range<Base>; friend constexpr iterator operator+(difference_type n, const iterator& i)requires random_access_range<Base>; friend constexpr iterator operator-(const iterator& i, difference_type n)requires random_access_range<Base>; friend constexpr difference_type operator-(const iterator& x, const iterator& y)requires sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>; };}
iterator::iterator_concept is defined as follows:
-
If Base models random_access_range, then iterator_concept denotes random_access_iterator_tag.
-
Otherwise, if Base models bidirectional_range, then iterator_concept denotes bidirectional_iterator_tag.
-
Otherwise, iterator_concept denotes forward_iterator_tag.
If the invocation of any non-const member function of iterator exits via an exception, the iterator acquires a singular value.
constexpr iterator(iterator_t<Base> current, range_difference_t<Base> n) requires (<Base>);
Effects: Initializes current_ with current andn_ with n.
constexpr iterator(iterator_t<Base> current, iterator_t<Base> last_ele, range_difference_t<Base> n) requires [slide-caches-first](#concept:slide-caches-first "25.7.30.2 Class template slide_view [range.slide.view]")<Base>;
Effects: Initializes current_ with current,last_ele_ with last_ele, andn_ with n.
constexpr iterator(iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<V>, iterator_t<Base>>;
Effects: Initializes current_ with std::move(i.current_) andn_ with i.n_.
[Note 1:
iterator can only be formed when Base models slide-caches-nothing, in which case last_ele_ is not present.
â end note]
constexpr auto operator*() const;
Returns: views::counted(current_, n_).
constexpr iterator& operator++();
Preconditions: current_ and last_ele_ (if present) are incrementable.
Postconditions: current_ and last_ele_ (if present) are each equal to ranges::next(i), where i is the value of that data member before the call.
Returns: *this.
constexpr iterator operator++(int);
Effects: Equivalent to:auto tmp = *this;++*this;return tmp;
constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Preconditions: current_ and last_ele_ (if present) are decrementable.
Postconditions: current_ and last_ele_ (if present) are each equal to ranges::prev(i), where i is the value of that data member before the call.
Returns: *this.
constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto tmp = *this;--*this;return tmp;
constexpr iterator& operator+=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Preconditions: current_ + x and last_ele_ + x (if last_ele_ is present) have well-defined behavior.
Postconditions: current_ and last_ele_ (if present) are each equal to i + x, where i is the value of that data member before the call.
Returns: *this.
constexpr iterator& operator-=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Preconditions: current_ - x and last_ele_ - x (if last_ele_ is present) have well-defined behavior.
Postconditions: current_ and last_ele_ (if present) are each equal to i - x, where i is the value of that data member before the call.
Returns: *this.
constexpr auto operator[](difference_type n) const requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return views::counted(current_ + n, n_);
friend constexpr bool operator==(const iterator& x, const iterator& y);
Returns: If last_ele_ is present,x.last_ele_ == y.last_ele_; otherwise, x.current_ == y.current_.
friend constexpr bool operator<(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Returns: x.current_ < y.current_.
friend constexpr bool operator>(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return y < x;
friend constexpr bool operator<=(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return !(y < x);
friend constexpr bool operator>=(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return !(x < y);
friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base> && [three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4 Concept three_way_comparable [cmp.concept]")<iterator_t<Base>>;
Returns: x.current_ <=> y.current_.
friend constexpr iterator operator+(const iterator& i, difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>; friend constexpr iterator operator+(difference_type n, const iterator& i) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto r = i; r += n;return r;
friend constexpr iterator operator-(const iterator& i, difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto r = i; r -= n;return r;
friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<iterator_t<Base>, iterator_t<Base>>;
Returns: If last_ele_ is present,x.last_ele_ - y.last_ele_; otherwise, x.current_ - y.current_.
25.7.30.4 Class slide_view::sentinel [range.slide.sentinel]
namespace std::ranges {template<forward_range V>requires viewclass slide_view::sentinel { sentinel_t end_ = sentinel_t(); // exposition onlyconstexpr explicit sentinel(sentinel_t end); // exposition onlypublic:sentinel() = default; friend constexpr bool operator==(const iterator& x, const sentinel& y); friend constexpr range_difference_toperator-(const iterator& x, const sentinel& y)requires sized_sentinel_for<sentinel_t, iterator_t>; friend constexpr range_difference_toperator-(const sentinel& y, const iterator& x)requires sized_sentinel_for<sentinel_t, iterator_t>; };}
[Note 1:
sentinel is used only when slide-caches-first is true.
â end note]
constexpr explicit sentinel(sentinel_t<V> end);
Effects: Initializes end_ with end.
friend constexpr bool operator==(const iterator<false>& x, const sentinel& y);
Returns: x.last_ele_ == y.end_.
friend constexpr range_difference_t<V> operator-(const iterator<false>& x, const sentinel& y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;
Returns: x.last_ele_ - y.end_.
friend constexpr range_difference_t<V> operator-(const sentinel& y, const iterator<false>& x) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;
Returns: y.end_ - x.last_ele_.
25.7.31 Chunk by view [range.chunk.by]
25.7.31.1 Overview [range.chunk.by.overview]
chunk_by_view takes a view and a predicate, and splits the view into subranges between each pair of adjacent elements for which the predicate returns false.
The name views::chunk_by denotes a range adaptor object ([range.adaptor.object]).
Given subexpressions E and F, the expression views::chunk_by(E, F) is expression-equivalent tochunk_by_view(E, F).
[Example 1: vector v = {1, 2, 2, 3, 0, 4, 5, 2};
for (auto r : v | views::chunk_by(ranges::less_equal{})) { cout << '['; auto sep = ""; for (auto i : r) { cout << sep << i; sep = ", "; } cout << "] ";}// The above prints [1, 2, 2, 3] [0, 4, 5] [2] â end example]
25.7.31.2 Class template chunk_by_view [range.chunk.by.view]
namespace std::ranges {template<forward_range V, indirect_binary_predicate<iterator_t, iterator_t> Pred>requires view && is_object_vclass chunk_by_view : public view_interface<chunk_by_view<V, Pred>> { V base_ = V(); // exposition only**movable-box pred_; // exposition only// [range.chunk.by.iter], class chunk_by_view::iteratorclass iterator; // exposition onlypublic: chunk_by_view() requires default_initializable && default_initializable = default; constexpr explicit chunk_by_view(V base, Pred pred); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr const Pred& pred() const; constexpr iterator begin(); constexpr auto end(); constexpr iterator_t find-next(iterator_t); // exposition onlyconstexpr iterator_t find-prev(iterator_t) // exposition onlyrequires bidirectional_range; }; template<class R, class Pred> chunk_by_view(R&&, Pred) -> chunk_by_view<views::all_t, Pred>;}
constexpr explicit chunk_by_view(V base, Pred pred);
Effects: Initializes base_ with std::move(base) andpred_ with std::move(pred).
constexpr const Pred& pred() const;
Effects: Equivalent to: return **pred_*;
constexpr iterator begin();
Preconditions: pred_.has_value() is true.
Returns: iterator(*this, ranges::begin(base_), find-next(ranges::begin(base_))).
Remarks: In order to provide the amortized constant-time complexity required by the range concept, this function caches the result within the chunk_by_view for use on subsequent calls.
constexpr auto end();
Effects: Equivalent to:if constexpr (common_range) {return iterator(*this, ranges::end(base_), ranges::end(base_));} else {return default_sentinel;}
constexpr iterator_t<V> find-next(iterator_t<V> current);
Preconditions: pred_.has_value() is true.
Returns: ranges::next(ranges::adjacent_find(current, ranges::end(base_), not_fn(ref(**pred_*))), 1, ranges::end(base_))
constexpr iterator_t<V> find-prev(iterator_t<V> current) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<V>;
Preconditions:
Returns: An iterator i in the range [ranges::begin(base_), current) such that:
ranges::adjacent_find(i, current, not_fn(ref(**pred_*))) is equal to current; and
if i is not equal to ranges::begin(base_), then bool(invoke(**pred_*, *ranges::prev(i), *i)) is false.
25.7.31.3 Class chunk_by_view::iterator [range.chunk.by.iter]
namespace std::ranges {template<forward_range V, indirect_binary_predicate<iterator_t, iterator_t> Pred>requires view && is_object_vclass chunk_by_view<V, Pred>::iterator { chunk_by_view* parent_ = nullptr; // exposition only iterator_t current_ = iterator_t(); // exposition only iterator_t next_ = iterator_t(); // exposition onlyconstexpr iterator(chunk_by_view& parent, iterator_t current, // exposition only iterator_t next); public:using value_type = subrange<iterator_t>; using difference_type = range_difference_t; using iterator_category = input_iterator_tag; using iterator_concept = see below; iterator() = default; constexpr value_type operator*() const; constexpr iterator& operator++(); constexpr iterator operator++(int); constexpr iterator& operator--() requires bidirectional_range; constexpr iterator operator--(int) requires bidirectional_range; friend constexpr bool operator==(const iterator& x, const iterator& y); friend constexpr bool operator==(const iterator& x, default_sentinel_t); };}
iterator::iterator_concept is defined as follows:
-
If V models bidirectional_range, then iterator_concept denotes bidirectional_iterator_tag.
-
Otherwise, iterator_concept denotes forward_iterator_tag.
constexpr iterator(chunk_by_view& parent, iterator_t<V> current, iterator_t<V> next);
Effects: Initializes parent_ with addressof(parent),current_ with current, andnext_ with next.
constexpr value_type operator*() const;
Preconditions: current_ is not equal to next_.
Returns: subrange(current_, next_).
constexpr iterator& operator++();
Preconditions: current_ is not equal to next_.
Effects: Equivalent to:current_ = next_;next_ = parent_->find-next(current_);return *this;
constexpr iterator operator++(int);
Effects: Equivalent to:auto tmp = *this;++*this;return tmp;
constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<V>;
Effects: Equivalent to:next_ = current_;current_ = parent_->find-prev(next_);return *this;
constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<V>;
Effects: Equivalent to:auto tmp = *this;--*this;return tmp;
friend constexpr bool operator==(const iterator& x, const iterator& y);
Returns: x.current_ == y.current_.
friend constexpr bool operator==(const iterator& x, default_sentinel_t);
Returns: x.current_ == x.next_.
25.7.32 Stride view [range.stride]
25.7.32.1 Overview [range.stride.overview]
stride_view presents a view of an underlying sequence, advancing over n elements at a time, as opposed to the usual single-step succession.
The name views::stride denotes a range adaptor object ([range.adaptor.object]).
Given subexpressions E and N, the expression views::stride(E, N) is expression-equivalent to stride_view(E, N).
[Example 1: auto input = views::iota(0, 12) | views::stride(3); ranges::copy(input, ostream_iterator(cout, " ")); // prints 0 3 6 9 ranges::copy(input | views::reverse, ostream_iterator(cout, " ")); // prints 9 6 3 0 â end example]
25.7.32.2 Class template stride_view [range.stride.view]
namespace std::ranges {template<input_range V>requires viewclass stride_view : public view_interface<stride_view> { V base_; // exposition only range_difference_t stride_; // exposition only// [range.stride.iterator], class template stride_view::iteratortemplate class iterator; // exposition onlypublic:constexpr explicit stride_view(V base, range_difference_t stride); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr range_difference_t stride() const noexcept; constexpr auto begin() requires () {return iterator(this, ranges::begin(base_)); }constexpr auto begin() const requires range {return iterator(this, ranges::begin(base_)); }constexpr auto end() requires (
) {if constexpr (common_range && sized_range && forward_range) {auto missing = (stride_ - ranges::distance(base_) % stride_) % stride_; return iterator(this, ranges::end(base_), missing); } else if constexpr (common_range &&
) {return iterator(this, ranges::end(base_)); } else {return default_sentinel; }}constexpr auto end() const requires range {if constexpr (common_range && sized_range && forward_range) {auto missing = (stride_ - ranges::distance(base_) % stride_) % stride_; return iterator(this, ranges::end(base_), missing); } else if constexpr (common_range &&
) {return iterator(this, ranges::end(base_)); } else {return default_sentinel; }}constexpr auto size() requires sized_range; constexpr auto size() const requires sized_range; constexpr auto reserve_hint() requires approximately_sized_range; constexpr auto reserve_hint() const requires approximately_sized_range; }; template stride_view(R&&, range_difference_t) -> stride_view<views::all_t>;}
constexpr stride_view(V base, range_difference_t<V> stride);
Preconditions: stride > 0 is true.
Effects: Initializes base_ with std::move(base) andstride_ with stride.
constexpr range_difference_t<V> stride() const noexcept;
Returns: stride_.
constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<V>; constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<const V>;
Effects: Equivalent to:return to-unsigned-like(div-ceil(ranges::distance(base_), stride_));
constexpr auto reserve_hint() requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3 Approximately sized ranges [range.approximately.sized]")<V>; constexpr auto reserve_hint() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3 Approximately sized ranges [range.approximately.sized]")<const V>;
Effects: Equivalent to:auto s = static_cast<range_difference_t<decltype((base_))>>(ranges::reserve_hint(base_));return to-unsigned-like(div-ceil(s, stride_));
25.7.32.3 Class template stride_view::iterator [range.stride.iterator]
namespace std::ranges {template<input_range V>requires viewtemplateclass stride_view::iterator {using Parent = maybe-const<Const, stride_view>; // exposition onlyusing Base = maybe-const<Const, V>; // exposition only iterator_t<Base> current_ = iterator_t<Base>(); // exposition only sentinel_t<Base> end_ = sentinel_t<Base>(); // exposition only range_difference_t<Base> stride_ = 0; // exposition only range_difference_t<Base> missing_ = 0; // exposition onlyconstexpr iterator(Parent* parent, iterator_t<Base> current, // exposition only range_difference_t<Base> missing = 0); public:using difference_type = range_difference_t<Base>; using value_type = range_value_t<Base>; using iterator_concept = see below; using iterator_category = see below; // not always presentiterator() requires default_initializable<iterator_t<Base>> = default; constexpr iterator(iterator other)requires Const && convertible_to<iterator_t, iterator_t<Base>>&& convertible_to<sentinel_t, sentinel_t<Base>>; constexpr iterator_t<Base> base() &&; constexpr const iterator_t<Base>& base() const & noexcept; constexpr decltype(auto) operator*() const { return **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) constrequires random_access_range<Base>{ return *(*this + n); }friend constexpr bool operator==(const iterator& x, default_sentinel_t); 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+(const iterator& x, difference_type n)requires random_access_range<Base>; friend constexpr iterator operator+(difference_type n, const iterator& x)requires random_access_range<Base>; friend constexpr iterator operator-(const iterator& x, difference_type n)requires random_access_range<Base>; friend constexpr difference_type operator-(const iterator& x, const iterator& y)requires sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>; friend constexpr difference_type operator-(default_sentinel_t y, const iterator& x)requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>; friend constexpr difference_type operator-(const iterator& x, default_sentinel_t y)requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>; friend constexpr range_rvalue_reference_t<Base> 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<Base>>; };}
iterator::iterator_concept is defined as follows:
-
If Base models random_access_range, then iterator_concept denotes random_access_iterator_tag.
-
Otherwise, if Base models bidirectional_range, then iterator_concept denotes bidirectional_iterator_tag.
-
Otherwise, if Base models forward_range, then iterator_concept denotes forward_iterator_tag.
-
Otherwise, iterator_concept denotes input_iterator_tag.
The member typedef-name iterator_category is defined if and only if Base models forward_range.
In that case,iterator::iterator_category is defined as follows:
-
Let C denote the type iterator_traits<iterator_t<Base>>::iterator_category.
-
If C modelsderived_from<random_access_iterator_tag>, then iterator_category denotes random_access_iterator_tag.
-
Otherwise, iterator_category denotes C.
constexpr iterator(Parent* parent, iterator_t<Base> current, range_difference_t<Base> missing = 0);
Effects: Initializes current_ with std::move(current),end_ with ranges::end(parent->base_),stride_ with parent->stride_, andmissing_ with missing.
constexpr iterator(iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<V>, iterator_t<Base>> && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;
Effects: Initializes current_ with std::move(i.current_),end_ with std::move(i.end_),stride_ with i.stride_, andmissing_ with i.missing_.
constexpr iterator_t<Base> base() &&;
Returns: std::move(current_).
constexpr const iterator_t<Base>& base() const & noexcept;
Returns: current_.
constexpr iterator& operator++();
Preconditions: current_ != end_ is true.
Effects: Equivalent to:missing_ = ranges::advance(current_, stride_, end_);return *this;
constexpr void operator++(int);
Effects: Equivalent to ++*this;
constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto tmp = *this;++*this;return tmp;
constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:ranges::advance(current_, missing_ - stride_);missing_ = 0;return *this;
constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto tmp = *this;--*this;return tmp;
constexpr iterator& operator+=(difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Preconditions: If n is positive,ranges::distance(current_, end_) > stride_ * (n - 1) is true.
[Note 1:
If n is negative, the Effects paragraph implies a precondition.
â end note]
Effects: Equivalent to:if (n > 0) { ranges::advance(current_, stride_ * (n - 1)); missing_ = ranges::advance(current_, stride_, end_);} else if (n < 0) { ranges::advance(current_, stride_ * n + missing_); missing_ = 0;}return *this;
constexpr iterator& operator-=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return *this += -x;
friend constexpr bool operator==(const iterator& x, default_sentinel_t);
Returns: x.current_ == x.end_.
friend constexpr bool operator==(const iterator& x, const iterator& y) requires [equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_comparable [concept.equalitycomparable]")<iterator_t<Base>>;
Returns: x.current_ == y.current_.
friend constexpr bool operator<(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Returns: x.current_ < y.current_.
friend constexpr bool operator>(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return y < x;
friend constexpr bool operator<=(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return !(y < x);
friend constexpr bool operator>=(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to: return !(x < y);
friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base> && [three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4 Concept three_way_comparable [cmp.concept]")<iterator_t<Base>>;
Returns: x.current_ <=> y.current_.
friend constexpr iterator operator+(const iterator& i, difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>; friend constexpr iterator operator+(difference_type n, const iterator& i) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto r = i; r += n;return r;
friend constexpr iterator operator-(const iterator& i, difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<Base>;
Effects: Equivalent to:auto r = i; r -= n;return r;
friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<iterator_t<Base>, iterator_t<Base>>;
Returns: Let N be (x.current_ - y.current_).
-
If Base models forward_range,(N + x.missing_ - y.missing_) / x.stride_.
-
Otherwise, if N is negative, -div-ceil(-N, x.stride_).
-
Otherwise, div-ceil(N, x.stride_).
friend constexpr difference_type operator-(default_sentinel_t y, const iterator& x) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<Base>>;
Returns: div-ceil(x.end_ - x.current_, x.stride_).
friend constexpr difference_type operator-(const iterator& x, default_sentinel_t y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<Base>>;
Effects: Equivalent to: return -(y - x);
friend constexpr range_rvalue_reference_t<Base> 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](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept indirectly_swappable [alg.req.ind.swap]")<iterator_t<Base>>;
Effects: Equivalent to:ranges::iter_swap(x.current_, y.current_);
25.7.33 Cartesian product view [range.cartesian]
25.7.33.1 Overview [range.cartesian.overview]
cartesian_product_view takes any non-zero number of ranges n and produces a view of tuples calculated by the n-ary cartesian product of the provided ranges.
The name views::cartesian_product denotes a customization point object ([customization.point.object]).
Given a pack of subexpressions Es, the expression views::cartesian_product(Es...) is expression-equivalent to
views::single(tuple()) if Es is an empty pack,
otherwise,cartesian_product_view<views::all_t<decltype((Es))>...>(Es...).
[Example 1: vector v { 0, 1, 2 };for (auto&& [a, b, c] : views::cartesian_product(v, v, v)) { cout << a << ' ' << b << ' ' << c << '\n';}// The above prints// 0 0 0// 0 0 1// 0 0 2// 0 1 0// 0 1 1// ... â end example]
25.7.33.2 Class template cartesian_product_view [range.cartesian.view]
namespace std::ranges {template<bool Const, class First, class... Vs>concept cartesian-product-is-random-access = // exposition only(random_access_range<maybe-const<Const, First>> && ... &&(random_access_range<maybe-const<Const, Vs>>&& sized_range<maybe-const<Const, Vs>>)); templateconcept cartesian-product-common-arg = // exposition onlycommon_range || (sized_range && random_access_range); template<bool Const, class First, class... Vs>concept cartesian-product-is-bidirectional = // exposition only(bidirectional_range<maybe-const<Const, First>> && ... &&(bidirectional_range<maybe-const<Const, Vs>>&& cartesian-product-common-arg<maybe-const<Const, Vs>>)); template<class First, class...>concept cartesian-product-is-common = // exposition onlycartesian-product-common-arg; template<class... Vs>concept cartesian-product-is-sized = // exposition only(sized_range && ...); template<bool Const, template class FirstSent, class First, class... Vs>concept cartesian-is-sized-sentinel = // exposition only(sized_sentinel_for<FirstSent<maybe-const<Const, First>>,
iterator_t<maybe-const<Const, First>>> && ...&& (sized_range<maybe-const<Const, Vs>>&& sized_sentinel_for<iterator_t<maybe-const<Const, Vs>>,
iterator_t<maybe-const<Const, Vs>>>)); template<cartesian-product-common-arg R>constexpr auto cartesian-common-arg-end(R& r) { // exposition onlyif constexpr (common_range) {return ranges::end(r); } else {return ranges::begin(r) + ranges::distance(r); }}template<input_range First, forward_range... Vs>requires (view && ... && view)class cartesian_product_view : public view_interface<cartesian_product_view<First, Vs...>> {private: tuple<First, Vs...> bases_; // exposition only// [range.cartesian.iterator], class template cartesian_product_view::iteratortemplate class iterator; // exposition onlypublic:constexpr cartesian_product_view() = default; constexpr explicit cartesian_product_view(First first_base, Vs... bases); constexpr iterator begin()requires ( || ... ||
); constexpr iterator begin() constrequires (range && ... && range); constexpr iterator end()requires ((
|| ... ||
) &&cartesian-product-is-common<First, Vs...>); constexpr iterator end() constrequires cartesian-product-is-common<const First, const Vs...>; constexpr default_sentinel_t end() const noexcept; constexpr see below size()requires cartesian-product-is-sized<First, Vs...>; constexpr see below size() constrequires cartesian-product-is-sized<const First, const Vs...>; }; template<class... Vs> cartesian_product_view(Vs&&...) -> cartesian_product_view<views::all_t...>;}
constexpr explicit cartesian_product_view(First first_base, Vs... bases);
Effects: Initializes bases_ with std::move(first_base), std::move(bases)....
constexpr iterator<false> begin() requires (<First> || ... || <Vs>);
Effects: Equivalent to:return iterator(*this, tuple-transform(ranges::begin, bases_));
constexpr iterator<true> begin() const requires ([range](range.range#concept:range "25.4.2 Ranges [range.range]")<const First> && ... && [range](range.range#concept:range "25.4.2 Ranges [range.range]")<const Vs>);
Effects: Equivalent to:return iterator(*this, tuple-transform(ranges::begin, bases_));
constexpr iterator<false> end() requires ((<First> || ... || <Vs>) && [cartesian-product-is-common](#concept:cartesian-product-is-common "25.7.33.2 Class template cartesian_product_view [range.cartesian.view]")<First, Vs...>); constexpr iterator<true> end() const requires [cartesian-product-is-common](#concept:cartesian-product-is-common "25.7.33.2 Class template cartesian_product_view [range.cartesian.view]")<const First, const Vs...>;
Let:
is-const be true for the const-qualified overload, andfalse otherwise;
is-empty be true if the expression ranges::empty(rng) is true for any rng among the underlying ranges except the first one andfalse otherwise; and
begin-or-first-end(rng) be expression-equivalent tois-empty ? ranges::begin(rng) : cartesian-common-arg-end(rng) if rng is the first underlying range andranges::begin(rng) otherwise.
Effects: Equivalent to:iterator<is-const> it(*this, tuple-transform([](auto& rng){ return begin-or-first-end(rng); }, bases_));return it;
constexpr default_sentinel_t end() const noexcept;
Returns: default_sentinel.
constexpr see below size() requires [cartesian-product-is-sized](#concept:cartesian-product-is-sized "25.7.33.2 Class template cartesian_product_view [range.cartesian.view]")<First, Vs...>; constexpr see below size() const requires [cartesian-product-is-sized](#concept:cartesian-product-is-sized "25.7.33.2 Class template cartesian_product_view [range.cartesian.view]")<const First, const Vs...>;
The return type is an implementation-defined unsigned-integer-like type.
Recommended practice: The return type should be the smallest unsigned-integer-like type that is sufficiently wide to store the product of the maximum sizes of all the underlying ranges, if such a type exists.
Let p be the product of the sizes of all the ranges in bases_.
Preconditions: p can be represented by the return type.
Returns: p.
25.7.33.3 Class template cartesian_product_view::iterator [range.cartesian.iterator]
namespace std::ranges {template<input_range First, forward_range... Vs>requires (view && ... && view)templateclass cartesian_product_view<First, Vs...>::iterator {public:using iterator_category = input_iterator_tag; using iterator_concept = see below; using value_type = tuple<range_value_t<maybe-const<Const, First>>, range_value_t<maybe-const<Const, Vs>>...>; using reference = tuple<range_reference_t<maybe-const<Const, First>>, range_reference_t<maybe-const<Const, Vs>>...>; using difference_type = see below; iterator() = default; constexpr iterator(iterator i) requires Const &&(convertible_to<iterator_t, iterator_t> &&... && convertible_to<iterator_t, iterator_t>); constexpr auto operator*() const; constexpr iterator& operator++(); constexpr void operator++(int); constexpr iterator operator++(int) requires forward_range<maybe-const<Const, First>>; constexpr iterator& operator--()requires cartesian-product-is-bidirectional<Const, First, Vs...>; constexpr iterator operator--(int)requires cartesian-product-is-bidirectional<Const, First, Vs...>; constexpr iterator& operator+=(difference_type x)requires cartesian-product-is-random-access<Const, First, Vs...>; constexpr iterator& operator-=(difference_type x)requires cartesian-product-is-random-access<Const, First, Vs...>; constexpr reference operator[](difference_type n) constrequires cartesian-product-is-random-access<Const, First, Vs...>; friend constexpr bool operator==(const iterator& x, const iterator& y)requires equality_comparable<iterator_t<maybe-const<Const, First>>>; friend constexpr bool operator==(const iterator& x, default_sentinel_t); friend constexpr auto operator<=>(const iterator& x, const iterator& y)requires all-random-access<Const, First, Vs...>; friend constexpr iterator operator+(const iterator& x, difference_type y)requires cartesian-product-is-random-access<Const, First, Vs...>; friend constexpr iterator operator+(difference_type x, const iterator& y)requires cartesian-product-is-random-access<Const, First, Vs...>; friend constexpr iterator operator-(const iterator& x, difference_type y)requires cartesian-product-is-random-access<Const, First, Vs...>; friend constexpr difference_type operator-(const iterator& x, const iterator& y)requires cartesian-is-sized-sentinel<Const, iterator_t, First, Vs...>; friend constexpr difference_type operator-(const iterator& i, default_sentinel_t)requires cartesian-is-sized-sentinel<Const, sentinel_t, First, Vs...>; friend constexpr difference_type operator-(default_sentinel_t, const iterator& i)requires cartesian-is-sized-sentinel<Const, sentinel_t, First, Vs...>; friend constexpr auto iter_move(const iterator& i) noexcept(see below); friend constexpr void iter_swap(const iterator& l, const iterator& r) noexcept(see below)requires (indirectly_swappable<iterator_t<maybe-const<Const, First>>> && ... &&indirectly_swappable<iterator_t<maybe-const<Const, Vs>>>); private:using Parent = maybe-const<Const, cartesian_product_view>; // *exposition onlyParent parent_ = nullptr; // exposition only tuple<iterator_t<maybe-const<Const, First>>, iterator_t<maybe-const<Const, Vs>>...> current_; // exposition onlytemplate<size_t N = sizeof...(Vs)>constexpr void next(); // exposition onlytemplate<size_t N = sizeof...(Vs)>constexpr void prev(); // exposition onlytemplateconstexpr difference_type distance-from(const Tuple& t) const; // exposition onlyconstexpr iterator(Parent& parent, tuple<iterator_t<maybe-const<Const, First>>, iterator_t<maybe-const<Const, Vs>>...> current); // exposition only};}
iterator::iterator_concept is defined as follows:
-
If cartesian-product-is-random-access<Const, First, Vs...> is modeled, then iterator_concept denotes random_access_iterator_tag.
-
Otherwise, if cartesian-product-is-bidirectional<Const, First, Vs...> is modeled, then iterator_concept denotes bidirectional_iterator_tag.
-
Otherwise, if maybe-const<Const, First> models forward_range, then iterator_concept denotes forward_iterator_tag.
-
Otherwise, iterator_concept denotes input_iterator_tag.
iterator::difference_type is an implementation-defined signed-integer-like type.
Recommended practice: iterator::difference_type should be the smallest signed-integer-like type that is sufficiently wide to store the product of the maximum sizes of all underlying ranges if such a type exists.
template<size_t N = sizeof...(Vs)> constexpr void next();
Effects: Equivalent to:auto& it = std::get(current_);++it;if constexpr (N > 0) {if (it == ranges::end(std::get(parent_->bases_))) { it = ranges::begin(std::get(parent_->bases_)); next<N - 1>(); }}
template<size_t N = sizeof...(Vs)> constexpr void prev();
Effects: Equivalent to:auto& it = std::get(current_);if constexpr (N > 0) {if (it == ranges::begin(std::get(parent_->bases_))) { it = cartesian-common-arg-end(std::get(parent_->bases_)); prev<N - 1>(); }}--it;
template<class Tuple> constexpr difference_type distance-from(const Tuple& t) const;
Let:
scaled-size(N) be the product ofstatic_cast<difference_type>(ranges::size(std::get<N>(parent_->bases_))) andscaled-size(N+1) if N ⤠sizeof...(Vs), otherwise static_cast<difference_type>(1);
scaled-distance(N) be the product ofstatic_cast<difference_type>(std::get(current_) - std::get(t)) and scaled-size(N+1); and
scaled-sum be the sum of scaled-distance(N) for every integer 0 ⤠N ⤠sizeof...(Vs).
Preconditions: scaled-sum can be represented by difference_type.
Returns: scaled-sum.
constexpr iterator(Parent& parent, tuple<iterator_t<maybe-const<Const, First>>, iterator_t<maybe-const<Const, Vs>>...> current);
Effects: Initializesparent_ with addressof(parent) andcurrent_ with std::move(current).
constexpr iterator(iterator<!Const> i) requires Const && ([convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<First>, iterator_t<const First>> && ... && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<Vs>, iterator_t<const Vs>>);
Effects: Initializesparent_ with i.parent_ andcurrent_ with std::move(i.current_).
constexpr auto operator*() const;
Effects: Equivalent to:return tuple-transform([](auto& i) -> decltype(auto) { return *i; }, current_);
constexpr iterator& operator++();
Effects: Equivalent to:next();return *this;
constexpr void operator++(int);
Effects: Equivalent to ++*this.
constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<maybe-const<Const, First>>;
Effects: Equivalent to:auto tmp = *this;++*this;return tmp;
constexpr iterator& operator--() requires [cartesian-product-is-bidirectional](#concept:cartesian-product-is-bidirectional "25.7.33.2 Class template cartesian_product_view [range.cartesian.view]")<Const, First, Vs...>;
Effects: Equivalent to:prev();return *this;
constexpr iterator operator--(int) requires [cartesian-product-is-bidirectional](#concept:cartesian-product-is-bidirectional "25.7.33.2 Class template cartesian_product_view [range.cartesian.view]")<Const, First, Vs...>;
Effects: Equivalent to:auto tmp = *this;--*this;return tmp;
constexpr iterator& operator+=(difference_type x) requires [cartesian-product-is-random-access](#concept:cartesian-product-is-random-access "25.7.33.2 Class template cartesian_product_view [range.cartesian.view]")<Const, First, Vs...>;
Let orig be the value of *this before the call.
Let ret be:
-
If x > 0, the value of *this had next been called x times.
-
Otherwise, if x < 0, the value of *this had prev been called -x times.
-
Otherwise, orig.
Preconditions: x is in the range[ranges::distance(this, ranges::begin(**parent_)),
ranges::distance(this, ranges::end(**parent_))].
Effects: Sets the value of *this to ret.
Returns: *this.
Complexity: Constant.
constexpr iterator& operator-=(difference_type x) requires [cartesian-product-is-random-access](#concept:cartesian-product-is-random-access "25.7.33.2 Class template cartesian_product_view [range.cartesian.view]")<Const, First, Vs...>;
Effects: Equivalent to:*this += -x;return *this;
constexpr reference operator[](difference_type n) const requires [cartesian-product-is-random-access](#concept:cartesian-product-is-random-access "25.7.33.2 Class template cartesian_product_view [range.cartesian.view]")<Const, First, Vs...>;
Effects: Equivalent to: return *((*this) + n);
friend constexpr bool operator==(const iterator& x, const iterator& y) requires [equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_comparable [concept.equalitycomparable]")<iterator_t<maybe-const<Const, First>>>;
Effects: Equivalent to: return x.current_ == y.current_;
friend constexpr bool operator==(const iterator& x, default_sentinel_t);
Returns: true if std::get(x.current_) == ranges::end(std::get(x.parent_->bases_)) is true for any integer 0 ⤠i ⤠sizeof...(Vs); otherwise, false.
friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires [all-random-access](#concept:all-random-access "25.7.5 Range adaptor helpers [range.adaptor.helpers]")<Const, First, Vs...>;
Effects: Equivalent to: return x.current_ <=> y.current_;
friend constexpr iterator operator+(const iterator& x, difference_type y) requires [cartesian-product-is-random-access](#concept:cartesian-product-is-random-access "25.7.33.2 Class template cartesian_product_view [range.cartesian.view]")<Const, First, Vs...>;
Effects: Equivalent to: return iterator(x) += y;
friend constexpr iterator operator+(difference_type x, const iterator& y) requires [cartesian-product-is-random-access](#concept:cartesian-product-is-random-access "25.7.33.2 Class template cartesian_product_view [range.cartesian.view]")<Const, First, Vs...>;
Effects: Equivalent to: return y + x;
friend constexpr iterator operator-(const iterator& x, difference_type y) requires [cartesian-product-is-random-access](#concept:cartesian-product-is-random-access "25.7.33.2 Class template cartesian_product_view [range.cartesian.view]")<Const, First, Vs...>;
Effects: Equivalent to: return iterator(x) -= y;
friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires [cartesian-is-sized-sentinel](#concept:cartesian-is-sized-sentinel "25.7.33.2 Class template cartesian_product_view [range.cartesian.view]")<Const, iterator_t, First, Vs...>;
Effects: Equivalent to: return x.distance-from(y.current_);
friend constexpr difference_type operator-(const iterator& i, default_sentinel_t) requires [cartesian-is-sized-sentinel](#concept:cartesian-is-sized-sentinel "25.7.33.2 Class template cartesian_product_view [range.cartesian.view]")<Const, sentinel_t, First, Vs...>;
Let end-tuple be an object of a type that is a specialization of tuple, such that:
std::get<0>(end-tuple) has the same value asranges::end(std::get<0>(i.parent_->bases_));
std::get(end-tuple) has the same value asranges::begin(std::get(i.parent_->bases_)) for every integer 1 ⤠N ⤠sizeof...(Vs).
Effects: Equivalent to: return i.distance-from(end-tuple);
friend constexpr difference_type operator-(default_sentinel_t s, const iterator& i) requires [cartesian-is-sized-sentinel](#concept:cartesian-is-sized-sentinel "25.7.33.2 Class template cartesian_product_view [range.cartesian.view]")<Const, sentinel_t, First, Vs...>;
Effects: Equivalent to: return -(i - s);
friend constexpr auto iter_move(const iterator& i) noexcept(see below);
Effects: Equivalent to: return tuple-transform(ranges::iter_move, i.current_);
Remarks: The exception specification is equivalent to the logical and of the following expressions:
noexcept(ranges::iter_move(std::get(i.current_))) for every integer
0 ⤠N ⤠sizeof...(Vs),
is_nothrow_move_constructible_v<range_rvalue_reference_t<maybe-const<Const, T>>>
for every type T in First, Vs....
friend constexpr void iter_swap(const iterator& l, const iterator& r) noexcept(see below) requires ([indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept indirectly_swappable [alg.req.ind.swap]")<iterator_t<maybe-const<Const, First>>> && ... && [indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept indirectly_swappable [alg.req.ind.swap]")<iterator_t<maybe-const<Const, Vs>>>);
Effects: For every integer 0 ⤠i ⤠sizeof...(Vs), performs:ranges::iter_swap(std::get(l.current_), std::get(r.current_))
Remarks: The exception specification is equivalent to the logical and of the following expressions:
noexcept(ranges::iter_swap(std::get(l.current_), std::get(r.current_))) for
every integer 0 ⤠i ⤠sizeof...(Vs).
25.7.34 Cache latest view [range.cache.latest]
25.7.34.1 Overview [range.cache.latest.overview]
cache_latest_view caches the last-accessed element of its underlying sequence so that the element does not have to be recomputed on repeated access.
[Note 1:
This is useful if computation of the element to produce is expensive.
â end note]
The name views::cache_latest denotes a range adaptor object ([range.adaptor.object]).
Let E be an expression.
The expression views::cache_latest(E) is expression-equivalent tocache_latest_view(E).
25.7.34.2 Class template cache_latest_view [range.cache.latest.view]
namespace std::ranges {template<input_range V>requires viewclass cache_latest_view : public view_interface<cache_latest_view> { V base_ = V(); // exposition onlyusing cache-t = conditional_t<is_reference_v<range_reference_t>, // exposition only add_pointer_t<range_reference_t>, range_reference_t>; non-propagating-cache<cache-t> cache_; // exposition only// [range.cache.latest.iterator], class cache_latest_view::iteratorclass iterator; // exposition only// [range.cache.latest.sentinel], class cache_latest_view::sentinelclass sentinel; // exposition onlypublic: cache_latest_view() requires default_initializable = default; constexpr explicit cache_latest_view(V base); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr auto begin(); constexpr auto end(); constexpr auto size() requires sized_range; constexpr auto size() const requires sized_range; constexpr auto reserve_hint() requires approximately_sized_range; constexpr auto reserve_hint() const requires approximately_sized_range; }; template cache_latest_view(R&&) -> cache_latest_view<views::all_t>;}
constexpr explicit cache_latest_view(V base);
Effects: Initializes base_ with std::move(base).
constexpr auto begin();
Effects: Equivalent to: return iterator(*this);
constexpr auto end();
Effects: Equivalent to: return sentinel(*this);
constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<V>; constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<const V>;
Effects: Equivalent to: return ranges::size(base_);
constexpr auto reserve_hint() requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3 Approximately sized ranges [range.approximately.sized]")<V>; constexpr auto reserve_hint() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3 Approximately sized ranges [range.approximately.sized]")<const V>;
Effects: Equivalent to: return ranges::reserve_hint(base_);
25.7.34.3 Class cache_latest_view::iterator [range.cache.latest.iterator]
namespace std::ranges {template<input_range V>requires viewclass cache_latest_view::iterator { cache_latest_view* parent_; // exposition only iterator_t current_; // exposition onlyconstexpr explicit iterator(cache_latest_view& parent); // exposition onlypublic:using difference_type = range_difference_t; using value_type = range_value_t; using iterator_concept = input_iterator_tag; iterator(iterator&&) = default; iterator& operator=(iterator&&) = default; constexpr iterator_t base() &&; constexpr const iterator_t& base() const & noexcept; constexpr range_reference_t& operator*() const; constexpr iterator& operator++(); constexpr void operator++(int); friend constexpr range_rvalue_reference_t 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>; };}
constexpr explicit iterator(cache_latest_view& parent);
Effects: Initializes current_ withranges::begin(parent.base_) and parent_ with addressof(parent).
constexpr iterator_t<V> base() &&;
Returns: std::move(current_).
constexpr const iterator_t<V>& base() const & noexcept;
Returns: current_.
constexpr iterator& operator++();
Effects: Equivalent to:parent_->cache_.reset();++current_;return *this;
constexpr void operator++(int);
Effects: Equivalent to: ++*this.
constexpr range_reference_t<V>& operator*() const;
Effects: Equivalent to:if constexpr (is_reference_v<range_reference_t>) {if (!parent_->cache_) {parent_->cache_ = addressof(as-lvalue(**current_)); }return parent_->cache_;} else {if (!parent_->cache_) {parent_->cache_.emplace-deref(current_); }return **parent_->cache_;}
[Note 1:
Evaluations of operator* on the same iterator object can conflict ([intro.races]).
â end note]
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](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept indirectly_swappable [alg.req.ind.swap]")<iterator_t<V>>;
Effects: Equivalent toranges::iter_swap(x.current_, y.current_).
25.7.34.4 Class cache_latest_view::sentinel [range.cache.latest.sentinel]
namespace std::ranges {template<input_range V>requires viewclass cache_latest_view::sentinel { sentinel_t end_ = sentinel_t(); // exposition onlyconstexpr explicit sentinel(cache_latest_view& parent); // exposition onlypublic:sentinel() = default; constexpr sentinel_t base() const; friend constexpr bool operator==(const iterator& x, const sentinel& y); friend constexpr range_difference_t operator-(const iterator& x, const sentinel& y)requires sized_sentinel_for<sentinel_t, iterator_t>; friend constexpr range_difference_t operator-(const sentinel& x, const iterator& y)requires sized_sentinel_for<sentinel_t, iterator_t>; };}
constexpr explicit sentinel(cache_latest_view& parent);
Effects: Initializes end_ with ranges::end(parent.base_).
constexpr sentinel_t<V> base() const;
Returns: end_.
friend constexpr bool operator==(const iterator& x, const sentinel& y);
Returns: x.current_ == y.end_.
friend constexpr range_difference_t<V> operator-(const iterator& x, const sentinel& y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;
Returns: x.current_ - y.end_.
friend constexpr range_difference_t<V> operator-(const sentinel& x, const iterator& y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;
Returns: x.end_ - y.current_.
25.7.35 To input view [range.to.input]
25.7.35.1 Overview [range.to.input.overview]
to_input_view presents a view of an underlying sequence as an input-only non-common range.
[Note 1:
This is useful to avoid overhead that can be necessary to provide support for the operations needed for greater iterator strength.
â end note]
The name views::to_input denotes a range adaptor object ([range.adaptor.object]).
Let E be an expression and let T be decltype((E)).
The expression views::to_input(E) is expression-equivalent to:
-
views::all(E) if T models input_range, does not satisfy common_range, and does not satisfy forward_range.
-
Otherwise, to_input_view(E).
25.7.35.2 Class template to_input_view [range.to.input.view]
namespace std::ranges {template<input_range V>requires viewclass to_input_view : public view_interface<to_input_view> { V base_ = V(); // exposition only// [range.to.input.iterator], class template to_input_view::iteratortemplate class iterator; // exposition onlypublic: to_input_view() requires default_initializable = default; constexpr explicit to_input_view(V base); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr auto begin() requires (); constexpr auto begin() const requires range; constexpr auto end() requires (
); constexpr auto end() const requires range; constexpr auto size() requires sized_range; constexpr auto size() const requires sized_range; constexpr auto reserve_hint() requires approximately_sized_range; constexpr auto reserve_hint() const requires approximately_sized_range; }; template to_input_view(R&&) -> to_input_view<views::all_t>;}
constexpr explicit to_input_view(V base);
Effects: Initializes base_ with std::move(base).
constexpr auto begin() requires (<V>);
Effects: Equivalent to: return iterator(ranges::begin(base_));
constexpr auto begin() const requires [range](range.range#concept:range "25.4.2 Ranges [range.range]")<const V>;
Effects: Equivalent to: return iterator(ranges::begin(base_));
constexpr auto end() requires (<V>); constexpr auto end() const requires [range](range.range#concept:range "25.4.2 Ranges [range.range]")<const V>;
Effects: Equivalent to: return ranges::end(base_);
constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<V>; constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<const V>;
Effects: Equivalent to: return ranges::size(base_);
constexpr auto reserve_hint() requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3 Approximately sized ranges [range.approximately.sized]")<V>; constexpr auto reserve_hint() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3 Approximately sized ranges [range.approximately.sized]")<const V>;
Effects: Equivalent to: return ranges::reserve_hint(base_);
25.7.35.3 Class template to_input_view::iterator [range.to.input.iterator]
namespace std::ranges {template<input_range V>requires viewtemplateclass to_input_view::iterator {using Base = maybe-const<Const, V>; // exposition only iterator_t<Base> current_ = iterator_t<Base>(); // exposition onlyconstexpr explicit iterator(iterator_t<Base> current); // exposition onlypublic:using difference_type = range_difference_t<Base>; using value_type = range_value_t<Base>; using iterator_concept = input_iterator_tag; iterator() requires default_initializable<iterator_t<Base>> = default; iterator(iterator&&) = default; iterator& operator=(iterator&&) = default; constexpr iterator(iterator i)requires Const && convertible_to<iterator_t, iterator_t<Base>>; constexpr iterator_t<Base> base() &&; constexpr const iterator_t<Base>& base() const & noexcept; constexpr decltype(auto) operator*() const { return **current_*; }constexpr iterator& operator++(); constexpr void operator++(int); friend constexpr bool operator==(const iterator& x, const sentinel_t<Base>& y); friend constexpr difference_type operator-(const sentinel_t<Base>& y, const iterator& x)requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>; friend constexpr difference_type operator-(const iterator& x, const sentinel_t<Base>& y)requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>; friend constexpr range_rvalue_reference_t<Base> 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<Base>>; };}
constexpr explicit iterator(iterator_t<Base> current);
Effects: Initializes current_ with std::move(current).
constexpr iterator(iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<iterator_t<V>, iterator_t<Base>>;
Effects: Initializes current_ with std::move(i.current_).
constexpr iterator_t<Base> base() &&;
Returns: std::move(current_).
constexpr const iterator_t<Base>& base() const & noexcept;
Returns: current_.
constexpr iterator& operator++();
Effects: Equivalent to:++current_;return *this;
constexpr void operator++(int);
Effects: Equivalent to: ++*this;
friend constexpr bool operator==(const iterator& x, const sentinel_t<Base>& y);
Returns: x.current_ == y.
friend constexpr difference_type operator-(const sentinel_t<Base>& y, const iterator& x) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<Base>>;
Returns: y - x.current_.
friend constexpr difference_type operator-(const iterator& x, const sentinel_t<Base>& y) requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept sized_sentinel_for [iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<Base>>;
Returns: x.current_ - y.
friend constexpr range_rvalue_reference_t<Base> 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](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept indirectly_swappable [alg.req.ind.swap]")<iterator_t<Base>>;
Effects: Equivalent to: ranges::iter_swap(x.current_, y.current_);