Files
cppdraft_translate/cppdraft/range/adaptors.md
2025-10-25 03:02:53 +03:00

622 KiB
Raw Blame History

[range.adaptors]

25 Ranges library [ranges]

25.7 Range adaptors [range.adaptors]

25.7.1 General [range.adaptors.general]

1

#

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.

2

#

Range adaptors are declared in namespace std::ranges::views.

3

#

The bitwise or operator is overloaded for the purpose of creating adaptor chain pipelines.

The adaptors also support function call syntax with equivalent semantics.

4

#

[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]

1

#

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:

  • (1.1)

    Its target object is an object d of type decay_t<decltype((D))> direct-non-list-initialized with D.

  • (1.2)

    It has one bound argument entity, an object c of type decay_t<decltype((C))> direct-non-list-initialized with C.

  • (1.3)

    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.

2

#

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.

3

#

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.

4

#

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.

5

#

The behavior of a program that adds a specialization for range_adaptor_closure is undefined.

6

#

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.

7

#

If a range adaptor object accepts only one argument, then it is a range adaptor closure object.

8

#

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:

  • (8.1)

    Its target object is a copy of adaptor.

  • (8.2)

    Its bound argument entities bound_args consist of objects of types BoundArgs... direct-non-list-initialized with std::forward<decltype((args))>(args)..., respectively.

  • (8.3)

    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]

1

#

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

2

#

Recommended practice:

  • (2.1)

    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.

  • (2.2)

    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]

1

#

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.

2

#

[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]

1

#

views::all returns a view that includes all elements of its range argument.

2

#

The name views::all denotes a range adaptor object ([range.adaptor.object]).

Given a subexpression E, the expressionviews::all(E) is expression-equivalent to:

  • (2.1)

    decay-copy(E) if the decayed type of E models view.

  • (2.2)

    Otherwise, ref_view{E} if that expression is well-formed.

  • (2.3)

    Otherwise, owning_view{E}.

25.7.6.2 Class template ref_view [range.ref.view]

1

#

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.2Helper concepts[range.utility.helpers]")<ref_view> T> requires see below constexpr ref_view(T&& t);

2

#

Effects: Initializes r_ withaddressof(static_cast<R&>(std::forward(t))).

3

#

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]

1

#

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

2

#

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]

1

#

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.

2

#

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:

  • (2.1)

    views::all(E) ifT models input_range andsame_as<range_rvalue_reference_t, range_reference_t> is true.

  • (2.2)

    Otherwise, as_rvalue_view(E).

3

#

[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 (simple-view){ return move_iterator(ranges::begin(base_)); }constexpr auto begin() const requires range{ return move_iterator(ranges::begin(base_)); }constexpr auto end() requires (simple-view) {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);

1

#

Effects: Initializes base_ with std::move(base).

25.7.8 Filter view [range.filter]

25.7.8.1 Overview [range.filter.overview]

1

#

filter_view presents a view of the elements of an underlying sequence that satisfy a predicate.

2

#

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).

3

#

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

1

#

Effects: Initializes base_ with std::move(base) and initializespred_ with std::move(pred).

🔗

constexpr const Pred& pred() const;

2

#

Effects: Equivalent to: return **pred_*;

🔗

constexpr iterator begin();

3

#

Preconditions: pred_.has_value() is true.

4

#

Returns: {this, ranges::find_if(base_, ref(**pred_))}.

5

#

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

1

#

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.

2

#

iterator::iterator_concept is defined as follows:

  • (2.1)

    If V models bidirectional_range, theniterator_concept denotes bidirectional_iterator_tag.

  • (2.2)

    Otherwise, if V models forward_range, theniterator_concept denotes forward_iterator_tag.

  • (2.3)

    Otherwise, iterator_concept denotes input_iterator_tag.

3

#

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:

  • (3.1)

    Let C denote the typeiterator_traits<iterator_t>::iterator_category.

  • (3.2)

    If C modelsderived_from<bidirectional_iterator_tag>, then iterator_category denotes bidirectional_iterator_tag.

  • (3.3)

    Otherwise, if C modelsderived_from<forward_iterator_tag>, then iterator_category denotes forward_iterator_tag.

  • (3.4)

    Otherwise, iterator_category denotes C.

🔗

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

4

#

Effects: Initializes current_ with std::move(current) andparent_ with addressof(parent).

🔗

constexpr const iterator_t<V>& base() const & noexcept;

5

#

Effects: Equivalent to: return current_;

🔗

constexpr iterator_t<V> base() &&;

6

#

Effects: Equivalent to: return std::move(current_);

🔗

constexpr range_reference_t<V> operator*() const;

7

#

Effects: Equivalent to: return **current_*;

🔗

constexpr iterator_t<V> operator->() const requires [has-arrow](range.utility.helpers#concept:has-arrow "25.5.2Helper concepts[range.utility.helpers]")<iterator_t<V>> && [copyable](concepts.object#concept:copyable "18.6Object concepts[concepts.object]")<iterator_t<V>>;

8

#

Effects: Equivalent to: return current_;

🔗

constexpr iterator& operator++();

9

#

Effects: Equivalent to:current_ = ranges::find_if(std::move(++current_), ranges::end(parent_->base_), ref(**parent_*->pred_));return *this;

🔗

constexpr void operator++(int);

10

#

Effects: Equivalent to ++*this.

🔗

constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>;

11

#

Effects: Equivalent to:auto tmp = *this;++*this;return tmp;

🔗

constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<V>;

12

#

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.6Other range refinements[range.refinements]")<V>;

13

#

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.4Concept equality_­comparable[concept.equalitycomparable]")<iterator_t<V>>;

14

#

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_)));

15

#

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.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<V>>;

16

#

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

1

#

Effects: Initializes end_ with ranges::end(parent.base_).

🔗

constexpr sentinel_t<V> base() const;

2

#

Effects: Equivalent to: return end_;

🔗

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

3

#

Effects: Equivalent to: return x.current_ == y.end_;

25.7.9 Transform view [range.transform]

25.7.9.1 Overview [range.transform.overview]

1

#

transform_view presents a view of an underlying sequence after applying a transformation function to each element.

2

#

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).

3

#

[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 &&regular_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 &&regular_invocable<const F&, range_reference_t>; constexpr sentinel end(); constexpr iterator end() requires common_range; constexpr sentinel end() constrequires range &&regular_invocable<const F&, range_reference_t>; constexpr iterator end() constrequires common_range &&regular_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);

1

#

Effects: Initializes base_ with std::move(base) andfun_ with std::move(fun).

🔗

constexpr iterator<false> begin();

2

#

Effects: Equivalent to:return iterator{*this, ranges::begin(base_)};

🔗

constexpr iterator<true> begin() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V> && [regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<const F&, range_reference_t<const V>>;

3

#

Effects: Equivalent to:return iterator{*this, ranges::begin(base_)};

🔗

constexpr sentinel<false> end();

4

#

Effects: Equivalent to:return sentinel{ranges::end(base_)};

🔗

constexpr iterator<false> end() requires [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V>;

5

#

Effects: Equivalent to:return iterator{*this, ranges::end(base_)};

🔗

constexpr sentinel<true> end() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V> && [regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<const F&, range_reference_t<const V>>;

6

#

Effects: Equivalent to:return sentinel{ranges::end(base_)};

🔗

constexpr iterator<true> end() const requires [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<const V> && [regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<const F&, range_reference_t<const V>>;

7

#

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

1

#

iterator::iterator_concept is defined as follows:

2

#

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.

  • (2.1)

    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.

  • (2.2)

    Otherwise, iterator_category denotes input_iterator_tag.

🔗

constexpr iterator(Parent& parent, iterator_t<Base> current);

3

#

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.4Concept convertible_­to[concept.convertible]")<iterator_t<V>, iterator_t<Base>>;

4

#

Effects: Initializes current_ with std::move(i.current_) andparent_ with i.parent_.

🔗

constexpr const iterator_t<Base>& base() const & noexcept;

5

#

Effects: Equivalent to: return current_;

🔗

constexpr iterator_t<Base> base() &&;

6

#

Effects: Equivalent to: return std::move(current_);

🔗

constexpr iterator& operator++();

7

#

Effects: Equivalent to:++current_;return *this;

🔗

constexpr void operator++(int);

8

#

Effects: Equivalent to ++current_.

🔗

constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;

9

#

Effects: Equivalent to:auto tmp = *this;++*this;return tmp;

🔗

constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

10

#

Effects: Equivalent to:--current_;return *this;

🔗

constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

11

#

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.6Other range refinements[range.refinements]")<Base>;

12

#

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.6Other range refinements[range.refinements]")<Base>;

13

#

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.4Concept equality_­comparable[concept.equalitycomparable]")<iterator_t<Base>>;

14

#

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.6Other range refinements[range.refinements]")<Base>;

15

#

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.6Other range refinements[range.refinements]")<Base>;

16

#

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.6Other range refinements[range.refinements]")<Base>;

17

#

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.6Other range refinements[range.refinements]")<Base>;

18

#

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.6Other range refinements[range.refinements]")<Base> && [three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]")<iterator_t<Base>>;

19

#

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.6Other 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.6Other range refinements[range.refinements]")<Base>;

20

#

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.6Other range refinements[range.refinements]")<Base>;

21

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<iterator_t<Base>, iterator_t<Base>>;

22

#

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 &&regular_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);

1

#

Effects: Initializes end_ with end.

🔗

constexpr sentinel(sentinel<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;

2

#

Effects: Initializes end_ with std::move(i.end_).

🔗

constexpr sentinel_t<Base> base() const;

3

#

Effects: Equivalent to: return end_;

🔗

template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept 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);

4

#

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.8Concept 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);

5

#

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.8Concept 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);

6

#

Effects: Equivalent to: return y.end_ - x.current_;

25.7.10 Take view [range.take]

25.7.10.1 Overview [range.take.overview]

1

#

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.

2

#

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

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)).

  • (2.5)

    Otherwise, take_view(E, F).

3

#

[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 (simple-view) {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 (simple-view) {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);

1

#

Preconditions: count >= 0 is true.

2

#

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

1

#

Effects: Initializes end_ with end.

🔗

constexpr sentinel(sentinel<!Const> s) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;

2

#

Effects: Initializes end_ with std::move(s.end_).

🔗

constexpr sentinel_t<Base> base() const;

3

#

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); `

4

#

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]

1

#

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)).

2

#

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).

3

#

[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 (simple-view){ return ranges::begin(base_); }constexpr auto begin() constrequires range &&indirect_unary_predicate<const Pred, iterator_t>{ return ranges::begin(base_); }constexpr auto end() requires (simple-view){ 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);

1

#

Effects: Initializes base_ with std::move(base) andpred_ with std::move(pred).

🔗

constexpr const Pred& pred() const;

2

#

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

1

#

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.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;

2

#

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); `

3

#

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]

1

#

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.

2

#

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:

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.

  • (2.3)

    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.

  • (2.4)

    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.

  • (2.5)

    Otherwise, drop_view(E, F).

3

#

[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 (simple-view){ 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);

1

#

Preconditions: count >= 0 is true.

2

#

Effects: Initializes base_ with std::move(base) andcount_ with count.

🔗

constexpr auto begin() requires (!([simple-view](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V> && [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<const V> && [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V>)); constexpr auto begin() const requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<const V> && [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V>;

3

#

Returns: ranges::next(ranges::begin(base_), count_, ranges::end(base_)).

4

#

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]

1

#

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)).

2

#

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).

3

#

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

1

#

Effects: Initializes base_ with std::move(base) andpred_ with std::move(pred).

🔗

constexpr const Pred& pred() const;

2

#

Effects: Equivalent to: return **pred_*;

🔗

constexpr auto begin();

3

#

Preconditions: pred_.has_value() is true.

4

#

Returns: ranges::find_if_not(base_, cref(**pred_*)).

5

#

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]

1

#

join_view flattens a view of ranges into a view.

2

#

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

3

#

[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 forward_rangenon-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);

1

#

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

1

#

iterator::iterator_concept is defined as follows:

  • (1.1)

    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.

  • (1.2)

    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.

  • (1.3)

    Otherwise, iterator_concept denotes input_iterator_tag.

2

#

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:

  • (2.1)

    Let OUTERC denote iterator_traits<iterator_t<Base>>::iterator_category, and let INNERC denote iterator_traits<iterator_t<range_reference_t<Base>>>::iterator_category.

  • (2.2)

    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.

  • (2.3)

    Otherwise, if OUTERC and INNERC each model derived_from<forward_iterator_tag>, iterator_category denotes forward_iterator_tag.

  • (2.4)

    Otherwise, iterator_category denotes input_iterator_tag.

3

#

iterator::difference_type denotes the type:common_type_t< range_difference_t<Base>, range_difference_t<range_reference_t<Base>>>

4

#

join_view iterators use the satisfy function to skip over empty inner ranges.

🔗

constexpr OuterIter& outer(); constexpr const OuterIter& outer() const;

5

#

Returns: outer_ if Base models forward_range; otherwise, **parent_*->outer_.

🔗

constexpr void satisfy();

6

#

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.6Other range refinements[range.refinements]")<Base>;

7

#

Effects: Initializes outer_ with std::move(outer) andparent_ with addressof(parent); then calls satisfy().

🔗

constexpr explicit iterator(Parent& parent) requires (![forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>);

8

#

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.4Concept convertible_­to[concept.convertible]")<iterator_t<V>, OuterIter> && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<InnerRng>, InnerIter>;

9

#

Effects: Initializes outer_ with std::move(i.outer_),inner_ with std::move(i.inner_), andparent_ with i.parent_.

10

#

[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.2Helper concepts[range.utility.helpers]")<InnerIter> && [copyable](concepts.object#concept:copyable "18.6Object concepts[concepts.object]")<InnerIter>;

11

#

Effects: Equivalent to: return **inner_*;

🔗

constexpr iterator& operator++();

12

#

Let inner-range be:

  • (12.1)

    If ref-is-glvalue is true, *outer().

  • (12.2)

    Otherwise, **parent_*->inner_.

13

#

Effects: Equivalent to:if (++*inner_ == ranges::end(as-lvalue(inner-range))) {++outer(); satisfy();}return *this;

🔗

constexpr void operator++(int);

14

#

Effects: Equivalent to: ++*this.

🔗

constexpr iterator operator++(int) requires ref-is-glvalue && [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base> && [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<Base>>;

15

#

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.6Other range refinements[range.refinements]")<Base> && [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<Base>> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<Base>>;

16

#

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.6Other range refinements[range.refinements]")<Base> && [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<Base>> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<Base>>;

17

#

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.6Other range refinements[range.refinements]")<Base> && [equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<iterator_t<range_reference_t<Base>>>;

18

#

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.4Concept indirectly_­swappable[alg.req.ind.swap]")<InnerIter>;

19

#

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

1

#

Effects: Initializes end_ with ranges::end(parent.base_).

🔗

constexpr sentinel(sentinel<!Const> s) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;

2

#

Effects: Initializes end_ with std::move(s.end_).

🔗

template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept 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);

3

#

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]

1

#

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.

2

#

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).

3

#

[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 forward_rangenon-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);

1

#

Effects: Initializes base_ with std::move(base) andpattern_ with std::move(pattern).

🔗

template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R> requires [constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<V, views::all_t<R>> && [constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<Pattern, single_view<range_value_t<InnerRng>>> constexpr explicit join_with_view(R&& r, range_value_t<InnerRng> e);

2

#

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 (forward_range<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_); }};}

1

#

iterator::iterator_concept is defined as follows:

  • (1.1)

    If ref-is-glvalue is true,Base models bidirectional_range, andInnerBase and PatternBase each model bidirectional-common, then iterator_concept denotes bidirectional_iterator_tag.

  • (1.2)

    Otherwise, if ref-is-glvalue is true andBase and InnerBase each model forward_range, then iterator_concept denotes forward_iterator_tag.

  • (1.3)

    Otherwise, iterator_concept denotes input_iterator_tag.

2

#

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:

  • (2.1)

    Let OUTERC denoteiterator_traits<OuterIter>::iterator_category, let INNERC denoteiterator_traits<InnerIter>::iterator_category, and let PATTERNC denoteiterator_traits<PatternIter>::iterator_category.

  • (2.2)

    Ifis_reference_v<common_reference_t<iter_reference_t<InnerIter>, iter_reference_t<PatternIter>>> is false,iterator_category denotes input_iterator_tag.

  • (2.3)

    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.

  • (2.4)

    Otherwise, if OUTERC, INNERC, and PATTERNC each model derived_from<forward_iterator_tag>,iterator_category denotes forward_iterator_tag.

  • (2.5)

    Otherwise, iterator_category denotes input_iterator_tag.

3

#

iterator::value_type denotes the type:common_type_t<iter_value_t<InnerIter>, iter_value_t<PatternIter>>

4

#

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;

5

#

Returns: outer_it_ if Base models forward_range; otherwise, **parent_*->outer_it_.

🔗

constexpr auto& update-inner();

6

#

Effects: Equivalent to:if constexpr (ref-is-glvalue)return as-lvalue(*outer());elsereturn parent_->inner_.emplace-deref(outer());

🔗

constexpr auto& get-inner();

7

#

Effects: Equivalent to:if constexpr (ref-is-glvalue)return as-lvalue(*outer());elsereturn **parent_*->inner_;

🔗

constexpr void satisfy();

8

#

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.6Other range refinements[range.refinements]")<Base>; constexpr explicit iterator(Parent& parent) requires (![forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>);

9

#

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.4Concept convertible_­to[concept.convertible]")<iterator_t<V>, OuterIter> && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<InnerRng>, InnerIter> && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<Pattern>, PatternIter>;

10

#

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_)));

11

#

[Note 2:

Const can only be true when Base models forward_range.

— end note]

🔗

constexpr decltype(auto) operator*() const;

12

#

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++();

13

#

Effects: Equivalent to:visit([](auto& it){ ++it; }, inner_it_);satisfy();return *this;

🔗

constexpr void operator++(int);

14

#

Effects: Equivalent to ++*this.

🔗

constexpr iterator operator++(int) requires ref-is-glvalue && [forward_iterator](iterator.concept.forward#concept:forward_iterator "24.3.4.11Concept forward_­iterator[iterator.concept.forward]")<OuterIter> && [forward_iterator](iterator.concept.forward#concept:forward_iterator "24.3.4.11Concept forward_­iterator[iterator.concept.forward]")<InnerIter>;

15

#

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.6Other range refinements[range.refinements]")<Base> && [bidirectional-common](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]")<InnerBase> && [bidirectional-common](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]")<PatternBase>;

16

#

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.6Other range refinements[range.refinements]")<Base> && [bidirectional-common](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]")<InnerBase> && [bidirectional-common](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]")<PatternBase>;

17

#

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.6Other range refinements[range.refinements]")<Base> && [equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<InnerIter>;

18

#

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

1

#

Effects: Initializes end_ with ranges::end(parent.base_).

🔗

constexpr sentinel(sentinel<!Const> s) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;

2

#

Effects: Initializes end_ with std::move(s.end_).

🔗

template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept 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);

3

#

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]

1

#

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.

2

#

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).

3

#

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

1

#

Effects: Initializes base_ with std::move(base), andpattern_ with std::move(pattern).

🔗

template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R> requires [constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<V, views::all_t<R>> && [constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<Pattern, single_view<range_value_t<R>>> constexpr explicit lazy_split_view(R&& r, range_value_t<R> e);

2

#

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 (forward_range<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); };}

1

#

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 (![forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>);

2

#

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.6Other range refinements[range.refinements]")<Base>;

3

#

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.4Concept convertible_­to[concept.convertible]")<iterator_t<V>, iterator_t<Base>>;

4

#

Effects: Initializes parent_ with i.parent_,current_ with std::move(i.current_), andtrailing_empty_ with i.trailing_empty_.

🔗

constexpr value_type operator*() const;

5

#

Effects: Equivalent to: return value_type{*this};

🔗

constexpr outer-iterator& operator++();

6

#

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.6Other range refinements[range.refinements]")<Base>;

7

#

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

8

#

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

1

#

Effects: Initializes i_ with std::move(i).

🔗

constexpr inner-iterator<Const> begin() const;

2

#

Effects: Equivalent to: return inner-iterator{i_};

🔗

constexpr default_sentinel_t end() const noexcept;

3

#

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

1

#

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

2

#

Effects: Initializes i_ with std::move(i).

🔗

constexpr const iterator_t<Base>& base() const & noexcept;

3

#

Effects: Equivalent to: return i_.current;

🔗

constexpr iterator_t<Base> base() && requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>;

4

#

Effects: Equivalent to: return std::move(i_.current);

🔗

constexpr inner-iterator& operator++();

5

#

Effects: Equivalent to:incremented_ = true;if constexpr (forward_range<Base>) {if constexpr (Pattern::size() == 0) {return *this; }}++i_.current;return *this;

🔗

friend constexpr bool operator==(const inner-iterator& x, const inner-iterator& y) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;

6

#

Effects: Equivalent to: return x.i_.current == y.i_.current;

🔗

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

7

#

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.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<Base>>;

8

#

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]

1

#

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.

2

#

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).

3

#

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

1

#

Effects: Initializes base_ with std::move(base), andpattern_ with std::move(pattern).

🔗

template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") R> requires [constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<V, views::all_t<R>> && [constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<Pattern, single_view<range_value_t<R>>> constexpr explicit split_view(R&& r, range_value_t<R> e);

2

#

Effects: Initializes base_ with views::all(std::forward(r)), andpattern_ with views::single(std::move(e)).

🔗

constexpr iterator begin();

3

#

Returns: {*this, ranges::begin(base_), find-next(ranges::begin(base_))}.

4

#

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

5

#

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

1

#

Effects: Initializes parent_ with addressof(parent),cur_ with std::move(current), andnext_ with std::move(next).

🔗

constexpr iterator_t<V> base() const;

2

#

Effects: Equivalent to: return cur_;

🔗

constexpr value_type operator*() const;

3

#

Effects: Equivalent to: return {cur_, next_.begin()};

🔗

constexpr iterator& operator++();

4

#

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

5

#

Effects: Equivalent to:auto tmp = *this;++*this;return tmp;

🔗

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

6

#

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

1

#

Effects: Initializes end_ with ranges::end(parent.base_).

🔗

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

2

#

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]

1

#

concat_view presents a view that concatenates all the underlying ranges.

2

#

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.2Class template concat_­view[range.concat.view]") = see below; // exposition only

1

#

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.2Class template concat_­view[range.concat.view]") = see below; // exposition only

2

#

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.2Class template concat_­view[range.concat.view]") = see below; // exposition only

3

#

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.2Class template concat_­view[range.concat.view]") = see below; // exposition only

4

#

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

5

#

Effects: Initializes views_ with std::move(views)....

🔗

constexpr iterator<false> begin() requires (!([simple-view](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Views> && ...)); constexpr iterator<true> begin() const requires ([range](range.range#concept:range "25.4.2Ranges[range.range]")<const Views> && ...) && [concatable](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<const Views...>;

6

#

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.2Helper concepts[range.utility.helpers]")<Views> && ...)); constexpr auto end() const requires ([range](range.range#concept:range "25.4.2Ranges[range.range]")<const Views> && ...) && [concatable](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<const Views...>;

7

#

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.4Sized ranges[range.sized]")<Views> && ...); constexpr auto size() const requires ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const Views> && ...);

8

#

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

1

#

iterator::iterator_concept is defined as follows:

  • (1.1)

    Ifconcat-is-random-access<Const, Views...> is modeled, then iterator_concept denotes random_access_iterator_tag.

  • (1.2)

    Otherwise, ifconcat-is-bidirectional<Const, Views...> is modeled, then iterator_concept denotes bidirectional_iterator_tag.

  • (1.3)

    Otherwise, ifall-forward<Const, Views...> is modeled, then iterator_concept denotes forward_iterator_tag.

  • (1.4)

    Otherwise, iterator_concept denotes input_iterator_tag.

2

#

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:

  • (2.1)

    Ifis_reference_v<concat-reference-t<maybe-const<Const, Views>...>> is false, then iterator_category denotes input_iterator_tag.

  • (2.2)

    Otherwise, let Cs denote the pack of typesiterator_traits<iterator_t<maybe-const<Const, Views>>>::iterator_category....

    • (2.2.1)

      If(derived_from<Cs, random_access_iterator_tag> && ...) && concat-is-random-access<Const, Views...> is true,iterator_category denotes random_access_iterator_tag.

    • (2.2.2)

      Otherwise, if(derived_from<Cs, bidirectional_iterator_tag> && ...) && concat-is-bidirectional<Const, Views...> is true,iterator_category denotes bidirectional_iterator_tag.

    • (2.2.3)

      Otherwise, if(derived_from<Cs, forward_iterator_tag> && ...) is true,iterator_category denotes forward_iterator_tag.

    • (2.2.4)

      Otherwise, iterator_category denotes input_iterator_tag.

🔗

template<size_t N> constexpr void satisfy();

3

#

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();

4

#

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

5

#

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

6

#

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.11Concept constructible_­from[concept.constructible]")<base-iter, Args&&...>;

7

#

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.4Concept convertible_­to[concept.convertible]")<iterator_t<Views>, iterator_t<const Views>> && ...);

8

#

Preconditions: it.it_.valueless_by_exception() is false.

9

#

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;

10

#

Preconditions: it_.valueless_by_exception() is false.

11

#

Effects: Equivalent to:using reference = concat-reference-t<maybe-const<Const, Views>...>;return std::visit([](auto&& it) -> reference { return *it; }, it_);

🔗

constexpr iterator& operator++();

12

#

Preconditions: it_.valueless_by_exception() is false.

13

#

Effects: Let i be it_.index().

Equivalent to:++std::get(it_);satisfy();return *this;

🔗

constexpr void operator++(int);

14

#

Effects: Equivalent to:++*this;

🔗

constexpr iterator operator++(int) requires [all-forward](#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;

15

#

Effects: Equivalent to:auto tmp = *this;++*this;return tmp;

🔗

constexpr iterator& operator--() requires [concat-is-bidirectional](#concept:concat-is-bidirectional "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>;

16

#

Preconditions: it_.valueless_by_exception() is false.

17

#

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.2Class template concat_­view[range.concat.view]")<Const, Views...>;

18

#

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.2Class template concat_­view[range.concat.view]")<Const, Views...>;

19

#

Preconditions: it_.valueless_by_exception() is false.

20

#

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.2Class template concat_­view[range.concat.view]")<Const, Views...>;

21

#

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.2Class template concat_­view[range.concat.view]")<Const, Views...>;

22

#

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.4Concept equality_­comparable[concept.equalitycomparable]")<iterator_t<maybe-const<Const, Views>>> && ...);

23

#

Preconditions: x.it_.valueless_by_exception() andy.it_.valueless_by_exception() are each false.

24

#

Effects: Equivalent to:return x.it_ == y.it_;

🔗

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

25

#

Preconditions: it.it_.valueless_by_exception() is false.

26

#

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.5Range 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.5Range 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.5Range 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.5Range 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.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> && ([three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]")<iterator_t<maybe-const<Const, Views>>> && ...));

27

#

Preconditions: x.it_.valueless_by_exception() andy.it_.valueless_by_exception() are each false.

28

#

Let op be the operator.

29

#

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.2Class template concat_­view[range.concat.view]")<Const, Views...>;

30

#

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.2Class template concat_­view[range.concat.view]")<Const, Views...>;

31

#

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.2Class template concat_­view[range.concat.view]")<Const, Views...>;

32

#

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.2Class template concat_­view[range.concat.view]")<Const, Views...>;

33

#

Preconditions: x.it_.valueless_by_exception() andy.it_.valueless_by_exception() are each false.

34

#

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;

35

#

Preconditions: x.it_.valueless_by_exception() is false.

36

#

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

37

#

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;

38

#

Effects: Equivalent to:return -(x - default_sentinel);

39

#

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

40

#

Preconditions: it.it_.valueless_by_exception() is false.

41

#

Effects: Equivalent to:return std::visit([](const auto& i)-> concat-rvalue-reference-t<maybe-const<Const, Views>...> {return ranges::iter_move(i); }, it.it_);

42

#

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;

43

#

Preconditions: x.it_.valueless_by_exception() andy.it_.valueless_by_exception() are each false.

44

#

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_);

45

#

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]

1

#

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.

2

#

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:

  • (2.1)

    If T models contiguous_iterator, then span(to_address(E), static_cast<size_t>(static_cast(F))).

  • (2.2)

    Otherwise, if T models random_access_iterator, then subrange(E, E + static_cast(F)), except that E is evaluated only once.

  • (2.3)

    Otherwise,subrange(counted_iterator(E, F), default_sentinel).

25.7.20 Common view [range.common]

25.7.20.1 Overview [range.common.overview]

1

#

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.

2

#

[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]

3

#

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:

  • (3.1)

    views::all(E), if decltype((E)) models common_range and views::all(E) is a well-formed expression.

  • (3.2)

    Otherwise, common_view{E}.

4

#

[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 (common_range && 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 (simple-view) {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 (simple-view) {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);

1

#

Effects: Initializes base_ with std::move(base).

25.7.21 Reverse view [range.reverse]

25.7.21.1 Overview [range.reverse.overview]

1

#

reverse_view takes a bidirectional view and produces another view that iterates the same elements in reverse order.

2

#

The name views::reverse denotes a range adaptor object ([range.adaptor.object]).

Given a subexpression E, the expressionviews::reverse(E) is expression-equivalent to:

  • (2.1)

    If the type of E is a (possibly cv-qualified) specialization of reverse_view, then E.base().

  • (2.2)

    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.

  • (2.3)

    Otherwise, reverse_view{E}.

3

#

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

1

#

Effects: Initializes base_ with std::move(base).

🔗

constexpr reverse_iterator<iterator_t<V>> begin();

2

#

Returns: make_reverse_iterator(ranges::next(ranges::begin(base_), ranges::end(base_)))

3

#

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.6Other range refinements[range.refinements]")<V>; constexpr auto begin() const requires [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<const V>;

4

#

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.6Other range refinements[range.refinements]")<const V>;

5

#

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]

1

#

as_const_view presents a view of an underlying sequence as constant.

That is, the elements of an as_const_view cannot be modified.

2

#

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:

  • (2.1)

    If views::all_t models constant_range, then views::all(E).

  • (2.2)

    Otherwise, if U denotes empty_view for some type X, then auto(views::empty).

  • (2.3)

    Otherwise, if U denotes span<X, Extent> for some type X and some extent Extent, then span<const X, Extent>(E).

  • (2.4)

    Otherwise, if U denotes ref_view for some type X andconst X models constant_range, then ref_view(static_cast<const X&>(E.base())).

  • (2.5)

    Otherwise, if E is an lvalue,const U models constant_range, andU does not model view, then ref_view(static_cast<const U&>(E)).

  • (2.6)

    Otherwise, as_const_view(E).

3

#

[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 (simple-view) { return ranges::cbegin(base_); }constexpr auto begin() const requires range { return ranges::cbegin(base_); }constexpr auto end() requires (simple-view) { 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);

1

#

Effects: Initializes base_ with std::move(base).

25.7.23 Elements view [range.elements]

25.7.23.1 Overview [range.elements.overview]

1

#

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.

2

#

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]

3

#

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]

4

#

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 (simple-view){ return iterator(ranges::begin(base_)); }constexpr auto begin() const requires range{ return iterator(ranges::begin(base_)); }constexpr auto end() requires (simple-view && common_range){ return sentinel{ranges::end(base_)}; }constexpr auto end() requires (simple-view && 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);

1

#

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

1

#

The member typedef-name iterator_concept is defined as follows:

2

#

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.

  • (2.1)

    If std::get(**current_*) is an rvalue,iterator_category denotes input_iterator_tag.

  • (2.2)

    Otherwise, if C models derived_from<random_access_iterator_tag>,iterator_category denotes random_access_iterator_tag.

  • (2.3)

    Otherwise, iterator_category denotes C.

🔗

static constexpr decltype(auto) get-element(const iterator_t<Base>& i);

3

#

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

4

#

Effects: Initializes current_ with std::move(current).

🔗

constexpr iterator(iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<V>, iterator_t<Base>>;

5

#

Effects: Initializes current_ with std::move(i.current_).

🔗

constexpr const iterator_t<Base>& base() const & noexcept;

6

#

Effects: Equivalent to: return current_;

🔗

constexpr iterator_t<Base> base() &&;

7

#

Effects: Equivalent to: return std::move(current_);

🔗

constexpr iterator& operator++();

8

#

Effects: Equivalent to:++current_;return *this;

🔗

constexpr void operator++(int);

9

#

Effects: Equivalent to: ++current_.

🔗

constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;

10

#

Effects: Equivalent to:auto temp = *this;++current_;return temp;

🔗

constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

11

#

Effects: Equivalent to:--current_;return *this;

🔗

constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

12

#

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.6Other range refinements[range.refinements]")<Base>;

13

#

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.6Other range refinements[range.refinements]")<Base>;

14

#

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.4Concept equality_­comparable[concept.equalitycomparable]")<Base>;

15

#

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.6Other range refinements[range.refinements]")<Base>;

16

#

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.6Other range refinements[range.refinements]")<Base>;

17

#

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.6Other range refinements[range.refinements]")<Base>;

18

#

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.6Other range refinements[range.refinements]")<Base>;

19

#

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.6Other range refinements[range.refinements]")<Base> && [three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]")<iterator_t<Base>>;

20

#

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.6Other range refinements[range.refinements]")<Base>;

21

#

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.6Other range refinements[range.refinements]")<Base>;

22

#

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.6Other range refinements[range.refinements]")<Base>;

23

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<iterator_t<Base>, iterator_t<Base>>;

24

#

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

1

#

Effects: Initializes end_ with end.

🔗

constexpr sentinel(sentinel<!Const> other) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;

2

#

Effects: Initializes end_ with std::move(other.end_).

🔗

constexpr sentinel_t<Base> base() const;

3

#

Effects: Equivalent to: return end_;

🔗

template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept 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);

4

#

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.8Concept 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);

5

#

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.8Concept 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);

6

#

Effects: Equivalent to: return x.end_ - y.current_;

25.7.24 Enumerate view [range.enumerate]

25.7.24.1 Overview [range.enumerate.overview]

1

#

enumerate_view is a view whose elements represent both the position and value from a sequence of elements.

2

#

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 (simple-view){ 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 (simple-view) {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);

1

#

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

1

#

The member typedef-nameiterator::iterator_concept is defined as follows:

🔗

constexpr explicit iterator(iterator_t<Base> current, difference_type pos);

2

#

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.4Concept convertible_­to[concept.convertible]")<iterator_t<V>, iterator_t<Base>>;

3

#

Effects: Initializes current_ with std::move(i.current_) andpos_ with i.pos_.

🔗

constexpr const iterator_t<Base>& base() const & noexcept;

4

#

Effects: Equivalent to: return current_;

🔗

constexpr iterator_t<Base> base() &&;

5

#

Effects: Equivalent to: return std::move(current_);

🔗

constexpr difference_type index() const noexcept;

6

#

Effects: Equivalent to: return pos_;

🔗

constexpr iterator& operator++();

7

#

Effects: Equivalent to:++current_;++pos_;return *this;

🔗

constexpr void operator++(int);

8

#

Effects: Equivalent to ++*this.

🔗

constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;

9

#

Effects: Equivalent to:auto temp = *this;++*this;return temp;

🔗

constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

10

#

Effects: Equivalent to:--current_;--pos_;return *this;

🔗

constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

11

#

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.6Other range refinements[range.refinements]")<Base>;

12

#

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.6Other range refinements[range.refinements]")<Base>;

13

#

Effects: Equivalent to:current_ -= n;pos_ -= n;return *this;

🔗

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

14

#

Effects: Equivalent to: return x.pos_ == y.pos_;

🔗

friend constexpr strong_ordering operator<=>(const iterator& x, const iterator& y) noexcept;

15

#

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.6Other range refinements[range.refinements]")<Base>;

16

#

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.6Other range refinements[range.refinements]")<Base>;

17

#

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.6Other range refinements[range.refinements]")<Base>;

18

#

Effects: Equivalent to:auto temp = x; temp -= y;return temp;

🔗

friend constexpr difference_type operator-(const iterator& x, const iterator& y) noexcept;

19

#

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

1

#

Effects: Initializes end_ with std::move(end).

🔗

constexpr sentinel(sentinel<!Const> other) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;

2

#

Effects: Initializes end_ with std::move(other.end_).

🔗

constexpr sentinel_t<Base> base() const;

3

#

Effects: Equivalent to: return end_;

🔗

template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept 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);

4

#

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.8Concept 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);

5

#

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.8Concept 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);

6

#

Effects: Equivalent to: return x.end_ - y.current_;

25.7.25 Zip view [range.zip]

25.7.25.1 Overview [range.zip.overview]

1

#

zip_view takes any number of views and produces a view of tuples of references to the corresponding elements of the constituent views.

2

#

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 (zip-is-common<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 (zip-is-common) {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...>;}

1

#

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

2

#

Effects: Initializes views_ with std::move(views)....

🔗

constexpr auto size() requires ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<Views> && ...); constexpr auto size() const requires ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const Views> && ...);

3

#

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>>> && ...); };}

1

#

iterator::iterator_concept is defined as follows:

  • (1.1)

    If all-random-access<Const, Views...> is modeled, then iterator_concept denotes random_access_iterator_tag.

  • (1.2)

    Otherwise, if all-bidirectional<Const, Views...> is modeled, then iterator_concept denotes bidirectional_iterator_tag.

  • (1.3)

    Otherwise, if all-forward<Const, Views...> is modeled, then iterator_concept denotes forward_iterator_tag.

  • (1.4)

    Otherwise, iterator_concept denotes input_iterator_tag.

2

#

iterator::iterator_category is present if and only if all-forward<Const, Views...> is modeled.

3

#

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

4

#

Effects: Initializes current_ with std::move(current).

🔗

constexpr iterator(iterator<!Const> i) requires Const && ([convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<Views>, iterator_t<const Views>> && ...);

5

#

Effects: Initializes current_ with std::move(i.current_).

🔗

constexpr auto operator*() const;

6

#

Effects: Equivalent to:return tuple-transform([](auto& i) -> decltype(auto) { return *i; }, current_);

🔗

constexpr iterator& operator++();

7

#

Effects: Equivalent to:tuple-for-each([](auto& i) { ++i; }, current_);return *this;

🔗

constexpr void operator++(int);

8

#

Effects: Equivalent to ++*this.

🔗

constexpr iterator operator++(int) requires [all-forward](#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;

9

#

Effects: Equivalent to:auto tmp = *this;++*this;return tmp;

🔗

constexpr iterator& operator--() requires [all-bidirectional](#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;

10

#

Effects: Equivalent to:tuple-for-each([](auto& i) { --i; }, current_);return *this;

🔗

constexpr iterator operator--(int) requires [all-bidirectional](#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;

11

#

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.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;

12

#

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.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;

13

#

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.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;

14

#

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.4Concept equality_­comparable[concept.equalitycomparable]")<iterator_t<maybe-const<Const, Views>>> && ...);

15

#

Returns:

  • (15.1)

    x.current_ == y.current_ if all-bidirectional<Const, Views...> is true.

  • (15.2)

    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]

  • (15.3)

    Otherwise, false.

🔗

friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires [all-random-access](#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;

16

#

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.5Range 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.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;

17

#

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.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;

18

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<iterator_t<maybe-const<Const, Views>>, iterator_t<maybe-const<Const, Views>>> && ...);

19

#

Let DIST(i) be difference_type(std::get(x.current_) - std::get(y.current_)).

20

#

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

21

#

Effects: Equivalent to:return tuple-transform(ranges::iter_move, i.current_);

22

#

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.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<maybe-const<Const, Views>>> && ...);

23

#

Effects: For every integer 0≤i<sizeof...(Views), performs:ranges::iter_swap(std::get(l.current_), std::get(r.current_))

24

#

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

1

#

Effects: Initializes end_ with end.

🔗

constexpr sentinel(sentinel<!Const> i) requires Const && ([convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<Views>, sentinel_t<const Views>> && ...);

2

#

Effects: Initializes end_ with std::move(i.end_).

🔗

template<bool OtherConst> requires ([sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept 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);

3

#

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.8Concept 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);

4

#

Let D be the return type.

Let DIST(i) beD(std::get(x.current_) - std::get(y.end_)).

5

#

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.8Concept 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);

6

#

Effects: Equivalent to: return -(x - y);

25.7.26 Zip transform view [range.zip.transform]

25.7.26.1 Overview [range.zip.transform.overview]

1

#

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.

2

#

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.

  • (2.1)

    If Es is an empty pack, let FD be decay_t<decltype((F))>.

If move_constructible &&regular_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&>>>))

  • (2.2)

    Otherwise, the expression views::zip_transform(F, Es...) is expression-equivalent to zip_transform_view(F, Es...).

3

#

[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 &&regular_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> &&regular_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> &&regular_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);

1

#

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

1

#

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.3Concept 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)
  • (1.2.2)

    Otherwise, if (derived_from<Cs, bidirectional_iterator_tag> && ...) is true,iterator_category denotes bidirectional_iterator_tag.

  • (1.2.3)

    Otherwise, if (derived_from<Cs, forward_iterator_tag> && ...) is true,iterator_category denotes forward_iterator_tag.

  • (1.2.4)

    Otherwise, iterator_category denotes input_iterator_tag.

🔗

constexpr iterator(Parent& parent, ziperator<Const> inner);

2

#

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.4Concept convertible_­to[concept.convertible]")<ziperator<false>, ziperator<Const>>;

3

#

Effects: Initializes parent_ with i.parent_ andinner_ with std::move(i.inner_).

🔗

constexpr decltype(auto) operator*() const noexcept(see below);

4

#

Effects: Equivalent to:return apply([&](const auto&... iters) -> decltype(auto) {return invoke(**parent_*->fun_, *iters...);}, inner_.current_);

5

#

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++();

6

#

Effects: Equivalent to:++inner_;return *this;

🔗

constexpr void operator++(int);

7

#

Effects: Equivalent to: ++*this.

🔗

constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;

8

#

Effects: Equivalent to:auto tmp = *this;++*this;return tmp;

🔗

constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

9

#

Effects: Equivalent to:--inner_;return *this;

🔗

constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

10

#

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.6Other range refinements[range.refinements]")<Base>;

11

#

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.6Other range refinements[range.refinements]")<Base>;

12

#

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.6Other range refinements[range.refinements]")<Base>;

13

#

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.4Concept 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.6Other range refinements[range.refinements]")<Base>;

14

#

Let op be the operator.

15

#

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.6Other 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.6Other range refinements[range.refinements]")<Base>;

16

#

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.6Other range refinements[range.refinements]")<Base>;

17

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<ziperator<Const>, ziperator<Const>>;

18

#

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 &&regular_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);

1

#

Effects: Initializes inner_ with inner.

🔗

constexpr sentinel(sentinel<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<zentinel<false>, zentinel<Const>>;

2

#

Effects: Initializes inner_ with std::move(i.inner_).

🔗

template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept sentinel_­for[iterator.concept.sentinel]")<zentinel<Const>, ziperator<OtherConst>> friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);

3

#

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.8Concept 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.8Concept 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);

4

#

Effects: Equivalent to: return x.inner_ - y.inner_;

25.7.27 Adjacent view [range.adjacent]

25.7.27.1 Overview [range.adjacent.overview]

1

#

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.

2

#

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]

3

#

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 (simple-view) {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 (simple-view) {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);

1

#

Effects: Initializes base_ with std::move(base).

🔗

constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>; constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V>;

2

#

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.3Approximately sized ranges[range.approximately.sized]")<V>; constexpr auto reserve_hint() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<const V>;

3

#

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

1

#

iterator::iterator_concept is defined as follows:

2

#

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

3

#

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

4

#

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.4Concept convertible_­to[concept.convertible]")<iterator_t<V>, iterator_t<Base>>;

5

#

Effects: Initializes each element of current_ with the corresponding element of i.current_ as an xvalue.

🔗

constexpr auto operator*() const;

6

#

Effects: Equivalent to:return tuple-transform([](auto& i) -> decltype(auto) { return *i; }, current_);

🔗

constexpr iterator& operator++();

7

#

Preconditions: current_.back() is incrementable.

8

#

Postconditions: Each element of current_ is equal to ranges::next(i), where i is the value of that element before the call.

9

#

Returns: *this.

🔗

constexpr iterator operator++(int);

10

#

Effects: Equivalent to:auto tmp = *this;++*this;return tmp;

🔗

constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

11

#

Preconditions: current_.front() is decrementable.

12

#

Postconditions: Each element of current_ is equal to ranges::prev(i), where i is the value of that element before the call.

13

#

Returns: *this.

🔗

constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

14

#

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.6Other range refinements[range.refinements]")<Base>;

15

#

Preconditions: current_.back() + x has well-defined behavior.

16

#

Postconditions: Each element of current_ is equal to i + x, where i is the value of that element before the call.

17

#

Returns: *this.

🔗

constexpr iterator& operator-=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<Base>;

18

#

Preconditions: current_.front() - x has well-defined behavior.

19

#

Postconditions: Each element of current_ is equal to i - x, where i is the value of that element before the call.

20

#

Returns: *this.

🔗

constexpr auto operator[](difference_type n) const requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<Base>;

21

#

Effects: Equivalent to:return tuple-transform([&](auto& i) -> decltype(auto) { return i[n]; }, current_);

🔗

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

22

#

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.6Other range refinements[range.refinements]")<Base>;

23

#

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.6Other range refinements[range.refinements]")<Base>;

24

#

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.6Other range refinements[range.refinements]")<Base>;

25

#

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.6Other range refinements[range.refinements]")<Base>;

26

#

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.6Other range refinements[range.refinements]")<Base> && [three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]")<iterator_t<Base>>;

27

#

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.6Other 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.6Other range refinements[range.refinements]")<Base>;

28

#

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.6Other range refinements[range.refinements]")<Base>;

29

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<iterator_t<Base>, iterator_t<Base>>;

30

#

Effects: Equivalent to:return x.current_.back() - y.current_.back();

🔗

friend constexpr auto iter_move(const iterator& i) noexcept(see below);

31

#

Effects: Equivalent to:return tuple-transform(ranges::iter_move, i.current_);

32

#

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.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<Base>>;

33

#

Preconditions: None of the iterators in l.current_ is equal to an iterator in r.current_.

34

#

Effects: For every integer 0≤i<N, performsranges::iter_swap(l.current_[i], r.current_[i]).

35

#

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

1

#

Effects: Initializes end_ with end.

🔗

constexpr sentinel(sentinel<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;

2

#

Effects: Initializes end_ with std::move(i.end_).

🔗

template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept 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);

3

#

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.8Concept 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);

4

#

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.8Concept 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);

5

#

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]

1

#

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.

2

#

The name views::adjacent_transform denotes a range adaptor object ([range.adaptor.object]).

Given subexpressions E and F and a constant expression N:

  • (2.1)

    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.

  • (2.2)

    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).

3

#

[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 &&regular_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> &&regular_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> &&regular_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);

1

#

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

1

#

The member typedef-name iterator::iterator_category is defined as follows:

  • (1.1)

    If invoke_result_t<maybe-const<Const, F>&,REPEAT(range_reference_t<Base>, N)...> is not a reference,iterator_category denotes input_iterator_tag.

  • (1.2)

    Otherwise, let C denote the typeiterator_traits<iterator_t<Base>>::iterator_category.

    • (1.2.1)

      If derived_from<C, random_access_iterator_tag> is true,iterator_category denotes random_access_iterator_tag.

    • (1.2.2)

      Otherwise, if derived_from<C, bidirectional_iterator_tag> is true,iterator_category denotes bidirectional_iterator_tag.

    • (1.2.3)

      Otherwise, if derived_from<C, forward_iterator_tag> is true,iterator_category denotes forward_iterator_tag.

    • (1.2.4)

      Otherwise, iterator_category denotes input_iterator_tag.

🔗

constexpr iterator(Parent& parent, inner-iterator<Const> inner);

2

#

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.4Concept convertible_­to[concept.convertible]")<inner-iterator<false>, inner-iterator<Const>>;

3

#

Effects: Initializes parent_ with i.parent_ andinner_ with std::move(i.inner_).

🔗

constexpr decltype(auto) operator*() const noexcept(see below);

4

#

Effects: Equivalent to:return apply([&](const auto&... iters) -> decltype(auto) {return invoke(**parent_*->fun_, *iters...);}, inner_.current_);

5

#

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++();

6

#

Effects: Equivalent to:++inner_;return *this;

🔗

constexpr iterator operator++(int);

7

#

Effects: Equivalent to:auto tmp = *this;++*this;return tmp;

🔗

constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

8

#

Effects: Equivalent to:--inner_;return *this;

🔗

constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

9

#

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.6Other range refinements[range.refinements]")<Base>;

10

#

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.6Other range refinements[range.refinements]")<Base>;

11

#

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.6Other range refinements[range.refinements]")<Base>;

12

#

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.6Other 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.6Other 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.6Other 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.6Other 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.6Other range refinements[range.refinements]")<Base> && [three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]")<inner-iterator<Const>>;

13

#

Let op be the operator.

14

#

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.6Other 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.6Other range refinements[range.refinements]")<Base>;

15

#

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.6Other range refinements[range.refinements]")<Base>;

16

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<inner-iterator<Const>, inner-iterator<Const>>;

17

#

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 &&regular_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);

1

#

Effects: Initializes inner_ with inner.

🔗

constexpr sentinel(sentinel<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<inner-sentinel<false>, inner-sentinel<Const>>;

2

#

Effects: Initializes inner_ with std::move(i.inner_).

🔗

template<bool OtherConst> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept sentinel_­for[iterator.concept.sentinel]")<inner-sentinel<Const>, inner-iterator<OtherConst>> friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);

3

#

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); `

4

#

Effects: Equivalent to: return x.inner_ - y.inner_;

25.7.29 Chunk view [range.chunk]

25.7.29.1 Overview [range.chunk.overview]

1

#

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.

2

#

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

1

#

Preconditions: n > 0 is true.

2

#

Effects: Initializes base_ with std::move(base) andn_ with n.

🔗

constexpr outer-iterator begin();

3

#

Effects: Equivalent to:current_ = ranges::begin(base_);remainder_ = n_;return outer-iterator(*this);

🔗

constexpr default_sentinel_t end() const noexcept;

4

#

Returns: default_sentinel.

🔗

constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>; constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V>;

5

#

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.3Approximately sized ranges[range.approximately.sized]")<V>; constexpr auto reserve_hint() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<const V>;

6

#

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

1

#

Effects: Initializes parent_ with addressof(parent).

🔗

constexpr value_type operator*() const;

2

#

Preconditions: *this == default_sentinel is false.

3

#

Returns: value_type(**parent_*).

🔗

constexpr outer-iterator& operator++();

4

#

Preconditions: *this == default_sentinel is false.

5

#

Effects: Equivalent to:ranges::advance(**parent_*->current_, parent_->remainder_, ranges::end(parent_->base_));parent_->remainder_ = parent_->n_;return *this;

🔗

constexpr void operator++(int);

6

#

Effects: Equivalent to ++*this.

🔗

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

7

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;

8

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;

9

#

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

1

#

Effects: Initializes parent_ with addressof(parent).

🔗

constexpr inner-iterator begin() const noexcept;

2

#

Returns: inner-iterator(**parent_*).

🔗

constexpr default_sentinel_t end() const noexcept;

3

#

Returns: default_sentinel.

🔗

constexpr auto size() const requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;

4

#

Effects: Equivalent to:return to-unsigned-like(ranges::min(parent_->remainder_, ranges::end(parent_->base_) - **parent_*->current_));

🔗

constexpr auto reserve_hint() const noexcept;

5

#

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;

1

#

Effects: Initializes parent_ with addressof(parent).

🔗

constexpr const iterator_t<V>& base() const &;

2

#

Effects: Equivalent to: return **parent_*->current_;

🔗

constexpr range_reference_t<V> operator*() const;

3

#

Preconditions: *this == default_sentinel is false.

4

#

Effects: Equivalent to: return **parent_->current_;

🔗

constexpr inner-iterator& operator++();

5

#

Preconditions: *this == default_sentinel is false.

6

#

Effects: Equivalent to:++**parent_->current_;if (**parent_->current_ == ranges::end(parent_->base_))parent_->remainder_ = 0;else--parent_->remainder_;return *this;

🔗

constexpr void operator++(int);

7

#

Effects: Equivalent to ++*this.

🔗

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

8

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;

9

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;

10

#

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_)));

11

#

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.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<V>>;

12

#

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 (simple-view) {return iterator(this, ranges::begin(base_)); }constexpr auto begin() const requires forward_range {return iterator(this, ranges::begin(base_)); }constexpr auto end() requires (simple-view) {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 && bidirectional_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 && bidirectional_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);

1

#

Preconditions: n > 0 is true.

2

#

Effects: Initializes base_ with std::move(base) andn_ with n.

🔗

constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>; constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V>;

3

#

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.3Approximately sized ranges[range.approximately.sized]")<V>; constexpr auto reserve_hint() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<const V>;

4

#

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

1

#

iterator::iterator_concept is defined as follows:

🔗

constexpr iterator(Parent* parent, iterator_t<Base> current, range_difference_t<Base> missing = 0);

2

#

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.4Concept convertible_­to[concept.convertible]")<iterator_t<V>, iterator_t<Base>> && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;

3

#

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;

4

#

Returns: current_.

🔗

constexpr value_type operator*() const;

5

#

Preconditions: current_ != end_ is true.

6

#

Returns: views::take(subrange(current_, end_), n_).

🔗

constexpr iterator& operator++();

7

#

Preconditions: current_ != end_ is true.

8

#

Effects: Equivalent to:missing_ = ranges::advance(current_, n_, end_);return *this;

🔗

constexpr iterator operator++(int);

9

#

Effects: Equivalent to:auto tmp = *this;++*this;return tmp;

🔗

constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

10

#

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.6Other range refinements[range.refinements]")<Base>;

11

#

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.6Other range refinements[range.refinements]")<Base>;

12

#

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]

13

#

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.6Other range refinements[range.refinements]")<Base>;

14

#

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.6Other range refinements[range.refinements]")<Base>;

15

#

Returns: *(*this + n).

🔗

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

16

#

Returns: x.current_ == y.current_.

🔗

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

17

#

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.6Other range refinements[range.refinements]")<Base>;

18

#

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.6Other range refinements[range.refinements]")<Base>;

19

#

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.6Other range refinements[range.refinements]")<Base>;

20

#

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.6Other range refinements[range.refinements]")<Base>;

21

#

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.6Other range refinements[range.refinements]")<Base> && [three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]")<iterator_t<Base>>;

22

#

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.6Other 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.6Other range refinements[range.refinements]")<Base>;

23

#

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.6Other range refinements[range.refinements]")<Base>;

24

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<iterator_t<Base>, iterator_t<Base>>;

25

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<Base>>;

26

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<Base>>;

27

#

Effects: Equivalent to: return -(y - x);

25.7.30 Slide view [range.slide]

25.7.30.1 Overview [range.slide.overview]

1

#

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.

2

#

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 onlyslide-caches-nothing && bidirectional_range && common_range; templateconcept slide-caches-first = // exposition onlyslide-caches-nothing && slide-caches-last; 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);

1

#

Preconditions: n > 0 is true.

2

#

Effects: Initializes base_ with std::move(base) andn_ with n.

🔗

constexpr auto begin() requires (!([simple-view](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V> && [slide-caches-nothing](#concept:slide-caches-nothing "25.7.30.2Class template slide_­view[range.slide.view]")<const V>));

3

#

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_).

4

#

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.2Class template slide_­view[range.slide.view]")<const V>;

5

#

Returns: iterator(ranges::begin(base_), n_).

🔗

constexpr auto end() requires (!([simple-view](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V> && [slide-caches-nothing](#concept:slide-caches-nothing "25.7.30.2Class template slide_­view[range.slide.view]")<const V>));

6

#

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_)).

7

#

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.2Class template slide_­view[range.slide.view]")<const V>;

8

#

Returns: begin() + range_difference_t(size()).

🔗

constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>; constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V>;

9

#

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.3Approximately sized ranges[range.approximately.sized]")<V>; constexpr auto reserve_hint() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<const V>;

10

#

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 (slide-caches-first<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>>; };}

1

#

iterator::iterator_concept is defined as follows:

2

#

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 (![slide-caches-first](#concept:slide-caches-first "25.7.30.2Class template slide_­view[range.slide.view]")<Base>);

3

#

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.2Class template slide_­view[range.slide.view]")<Base>;

4

#

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.4Concept convertible_­to[concept.convertible]")<iterator_t<V>, iterator_t<Base>>;

5

#

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;

6

#

Returns: views::counted(current_, n_).

🔗

constexpr iterator& operator++();

7

#

Preconditions: current_ and last_ele_ (if present) are incrementable.

8

#

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.

9

#

Returns: *this.

🔗

constexpr iterator operator++(int);

10

#

Effects: Equivalent to:auto tmp = *this;++*this;return tmp;

🔗

constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

11

#

Preconditions: current_ and last_ele_ (if present) are decrementable.

12

#

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.

13

#

Returns: *this.

🔗

constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

14

#

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.6Other range refinements[range.refinements]")<Base>;

15

#

Preconditions: current_ + x and last_ele_ + x (if last_ele_ is present) have well-defined behavior.

16

#

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.

17

#

Returns: *this.

🔗

constexpr iterator& operator-=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<Base>;

18

#

Preconditions: current_ - x and last_ele_ - x (if last_ele_ is present) have well-defined behavior.

19

#

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.

20

#

Returns: *this.

🔗

constexpr auto operator[](difference_type n) const requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<Base>;

21

#

Effects: Equivalent to: return views::counted(current_ + n, n_);

🔗

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

22

#

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.6Other range refinements[range.refinements]")<Base>;

23

#

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.6Other range refinements[range.refinements]")<Base>;

24

#

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.6Other range refinements[range.refinements]")<Base>;

25

#

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.6Other range refinements[range.refinements]")<Base>;

26

#

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.6Other range refinements[range.refinements]")<Base> && [three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]")<iterator_t<Base>>;

27

#

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.6Other 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.6Other range refinements[range.refinements]")<Base>;

28

#

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.6Other range refinements[range.refinements]")<Base>;

29

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<iterator_t<Base>, iterator_t<Base>>;

30

#

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

1

#

[Note 1:

sentinel is used only when slide-caches-first is true.

— end note]

🔗

constexpr explicit sentinel(sentinel_t<V> end);

2

#

Effects: Initializes end_ with end.

🔗

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

3

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;

4

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;

5

#

Returns: y.end_ - x.last_ele_.

25.7.31 Chunk by view [range.chunk.by]

25.7.31.1 Overview [range.chunk.by.overview]

1

#

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.

2

#

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

1

#

Effects: Initializes base_ with std::move(base) andpred_ with std::move(pred).

🔗

constexpr const Pred& pred() const;

2

#

Effects: Equivalent to: return **pred_*;

🔗

constexpr iterator begin();

3

#

Preconditions: pred_.has_value() is true.

4

#

Returns: iterator(*this, ranges::begin(base_), find-next(ranges::begin(base_))).

5

#

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();

6

#

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

7

#

Preconditions: pred_.has_value() is true.

8

#

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.6Other range refinements[range.refinements]")<V>;

9

#

Preconditions:

  • (9.1)

    current is not equal to ranges::begin(base_).

  • (9.2)

    pred_.has_value() is true.

10

#

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

1

#

iterator::iterator_concept is defined as follows:

  • (1.1)

    If V models bidirectional_range, then iterator_concept denotes bidirectional_iterator_tag.

  • (1.2)

    Otherwise, iterator_concept denotes forward_iterator_tag.

🔗

constexpr iterator(chunk_by_view& parent, iterator_t<V> current, iterator_t<V> next);

2

#

Effects: Initializes parent_ with addressof(parent),current_ with current, andnext_ with next.

🔗

constexpr value_type operator*() const;

3

#

Preconditions: current_ is not equal to next_.

4

#

Returns: subrange(current_, next_).

🔗

constexpr iterator& operator++();

5

#

Preconditions: current_ is not equal to next_.

6

#

Effects: Equivalent to:current_ = next_;next_ = parent_->find-next(current_);return *this;

🔗

constexpr iterator operator++(int);

7

#

Effects: Equivalent to:auto tmp = *this;++*this;return tmp;

🔗

constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<V>;

8

#

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.6Other range refinements[range.refinements]")<V>;

9

#

Effects: Equivalent to:auto tmp = *this;--*this;return tmp;

🔗

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

10

#

Returns: x.current_ == y.current_.

🔗

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

11

#

Returns: x.current_ == x.next_.

25.7.32 Stride view [range.stride]

25.7.32.1 Overview [range.stride.overview]

1

#

stride_view presents a view of an underlying sequence, advancing over n elements at a time, as opposed to the usual single-step succession.

2

#

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).

3

#

[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 (simple-view) {return iterator(this, ranges::begin(base_)); }constexpr auto begin() const requires range {return iterator(this, ranges::begin(base_)); }constexpr auto end() requires (simple-view) {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 && bidirectional_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 && bidirectional_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);

1

#

Preconditions: stride > 0 is true.

2

#

Effects: Initializes base_ with std::move(base) andstride_ with stride.

🔗

constexpr range_difference_t<V> stride() const noexcept;

3

#

Returns: stride_.

🔗

constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>; constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V>;

4

#

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.3Approximately sized ranges[range.approximately.sized]")<V>; constexpr auto reserve_hint() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<const V>;

5

#

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

1

#

iterator::iterator_concept is defined as follows:

2

#

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:

  • (2.1)

    Let C denote the type iterator_traits<iterator_t<Base>>::iterator_category.

  • (2.2)

    If C modelsderived_from<random_access_iterator_tag>, then iterator_category denotes random_access_iterator_tag.

  • (2.3)

    Otherwise, iterator_category denotes C.

🔗

constexpr iterator(Parent* parent, iterator_t<Base> current, range_difference_t<Base> missing = 0);

3

#

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.4Concept convertible_­to[concept.convertible]")<iterator_t<V>, iterator_t<Base>> && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;

4

#

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() &&;

5

#

Returns: std::move(current_).

🔗

constexpr const iterator_t<Base>& base() const & noexcept;

6

#

Returns: current_.

🔗

constexpr iterator& operator++();

7

#

Preconditions: current_ != end_ is true.

8

#

Effects: Equivalent to:missing_ = ranges::advance(current_, stride_, end_);return *this;

🔗

constexpr void operator++(int);

9

#

Effects: Equivalent to ++*this;

🔗

constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;

10

#

Effects: Equivalent to:auto tmp = *this;++*this;return tmp;

🔗

constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;

11

#

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.6Other range refinements[range.refinements]")<Base>;

12

#

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.6Other range refinements[range.refinements]")<Base>;

13

#

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]

14

#

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.6Other range refinements[range.refinements]")<Base>;

15

#

Effects: Equivalent to: return *this += -x;

🔗

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

16

#

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.4Concept equality_­comparable[concept.equalitycomparable]")<iterator_t<Base>>;

17

#

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.6Other range refinements[range.refinements]")<Base>;

18

#

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.6Other range refinements[range.refinements]")<Base>;

19

#

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.6Other range refinements[range.refinements]")<Base>;

20

#

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.6Other range refinements[range.refinements]")<Base>;

21

#

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.6Other range refinements[range.refinements]")<Base> && [three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]")<iterator_t<Base>>;

22

#

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.6Other 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.6Other range refinements[range.refinements]")<Base>;

23

#

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.6Other range refinements[range.refinements]")<Base>;

24

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<iterator_t<Base>, iterator_t<Base>>;

25

#

Returns: Let N be (x.current_ - y.current_).

  • (25.1)

    If Base models forward_range,(N + x.missing_ - y.missing_) / x.stride_.

  • (25.2)

    Otherwise, if N is negative, -div-ceil(-N, x.stride_).

  • (25.3)

    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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<Base>>;

26

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<Base>>;

27

#

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_)));

28

#

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.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<Base>>;

29

#

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]

1

#

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.

2

#

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...).

3

#

[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 (simple-view || ... || simple-view); constexpr iterator begin() constrequires (range && ... && range); constexpr iterator end()requires ((simple-view || ... || simple-view) &&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);

1

#

Effects: Initializes bases_ with std::move(first_base), std::move(bases)....

🔗

constexpr iterator<false> begin() requires (![simple-view](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<First> || ... || ![simple-view](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Vs>);

2

#

Effects: Equivalent to:return iterator(*this, tuple-transform(ranges::begin, bases_));

🔗

constexpr iterator<true> begin() const requires ([range](range.range#concept:range "25.4.2Ranges[range.range]")<const First> && ... && [range](range.range#concept:range "25.4.2Ranges[range.range]")<const Vs>);

3

#

Effects: Equivalent to:return iterator(*this, tuple-transform(ranges::begin, bases_));

🔗

constexpr iterator<false> end() requires ((![simple-view](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<First> || ... || ![simple-view](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Vs>) && [cartesian-product-is-common](#concept:cartesian-product-is-common "25.7.33.2Class 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.2Class template cartesian_­product_­view[range.cartesian.view]")<const First, const Vs...>;

4

#

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.

5

#

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;

6

#

Returns: default_sentinel.

🔗

constexpr see below size() requires [cartesian-product-is-sized](#concept:cartesian-product-is-sized "25.7.33.2Class 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.2Class template cartesian_­product_­view[range.cartesian.view]")<const First, const Vs...>;

7

#

The return type is an implementation-defined unsigned-integer-like type.

8

#

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.

9

#

Let p be the product of the sizes of all the ranges in bases_.

10

#

Preconditions: p can be represented by the return type.

11

#

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

1

#

iterator::iterator_concept is defined as follows:

2

#

iterator::difference_type is an implementation-defined signed-integer-like type.

3

#

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();

4

#

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();

5

#

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;

6

#

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).

7

#

Preconditions: scaled-sum can be represented by difference_type.

8

#

Returns: scaled-sum.

🔗

constexpr iterator(Parent& parent, tuple<iterator_t<maybe-const<Const, First>>, iterator_t<maybe-const<Const, Vs>>...> current);

9

#

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.4Concept convertible_­to[concept.convertible]")<iterator_t<First>, iterator_t<const First>> && ... && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<Vs>, iterator_t<const Vs>>);

10

#

Effects: Initializesparent_ with i.parent_ andcurrent_ with std::move(i.current_).

🔗

constexpr auto operator*() const;

11

#

Effects: Equivalent to:return tuple-transform([](auto& i) -> decltype(auto) { return *i; }, current_);

🔗

constexpr iterator& operator++();

12

#

Effects: Equivalent to:next();return *this;

🔗

constexpr void operator++(int);

13

#

Effects: Equivalent to ++*this.

🔗

constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<maybe-const<Const, First>>;

14

#

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.2Class template cartesian_­product_­view[range.cartesian.view]")<Const, First, Vs...>;

15

#

Effects: Equivalent to:prev();return *this;

🔗

constexpr iterator operator--(int) requires [cartesian-product-is-bidirectional](#concept:cartesian-product-is-bidirectional "25.7.33.2Class template cartesian_­product_­view[range.cartesian.view]")<Const, First, Vs...>;

16

#

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.2Class template cartesian_­product_­view[range.cartesian.view]")<Const, First, Vs...>;

17

#

Let orig be the value of *this before the call.

Let ret be:

  • (17.1)

    If x > 0, the value of *this had next been called x times.

  • (17.2)

    Otherwise, if x < 0, the value of *this had prev been called -x times.

  • (17.3)

    Otherwise, orig.

18

#

Preconditions: x is in the range[ranges::distance(this, ranges::begin(**parent_)),
ranges::distance(this, ranges::end(**parent_))].

19

#

Effects: Sets the value of *this to ret.

20

#

Returns: *this.

21

#

Complexity: Constant.

🔗

constexpr iterator& operator-=(difference_type x) requires [cartesian-product-is-random-access](#concept:cartesian-product-is-random-access "25.7.33.2Class template cartesian_­product_­view[range.cartesian.view]")<Const, First, Vs...>;

22

#

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.2Class template cartesian_­product_­view[range.cartesian.view]")<Const, First, Vs...>;

23

#

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.4Concept equality_­comparable[concept.equalitycomparable]")<iterator_t<maybe-const<Const, First>>>;

24

#

Effects: Equivalent to: return x.current_ == y.current_;

🔗

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

25

#

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.5Range adaptor helpers[range.adaptor.helpers]")<Const, First, Vs...>;

26

#

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.2Class template cartesian_­product_­view[range.cartesian.view]")<Const, First, Vs...>;

27

#

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.2Class template cartesian_­product_­view[range.cartesian.view]")<Const, First, Vs...>;

28

#

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.2Class template cartesian_­product_­view[range.cartesian.view]")<Const, First, Vs...>;

29

#

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.2Class template cartesian_­product_­view[range.cartesian.view]")<Const, iterator_t, First, Vs...>;

30

#

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.2Class template cartesian_­product_­view[range.cartesian.view]")<Const, sentinel_t, First, Vs...>;

31

#

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).

32

#

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.2Class template cartesian_­product_­view[range.cartesian.view]")<Const, sentinel_t, First, Vs...>;

33

#

Effects: Equivalent to: return -(i - s);

🔗

friend constexpr auto iter_move(const iterator& i) noexcept(see below);

34

#

Effects: Equivalent to: return tuple-transform(ranges::iter_move, i.current_);

35

#

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.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<maybe-const<Const, First>>> && ... && [indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<maybe-const<Const, Vs>>>);

36

#

Effects: For every integer 0 ≤ i ≤ sizeof...(Vs), performs:ranges::iter_swap(std::get(l.current_), std::get(r.current_))

37

#

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]

1

#

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]

2

#

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

1

#

Effects: Initializes base_ with std::move(base).

🔗

constexpr auto begin();

2

#

Effects: Equivalent to: return iterator(*this);

🔗

constexpr auto end();

3

#

Effects: Equivalent to: return sentinel(*this);

🔗

constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>; constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V>;

4

#

Effects: Equivalent to: return ranges::size(base_);

🔗

constexpr auto reserve_hint() requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<V>; constexpr auto reserve_hint() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<const V>;

5

#

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

1

#

Effects: Initializes current_ withranges::begin(parent.base_) and parent_ with addressof(parent).

🔗

constexpr iterator_t<V> base() &&;

2

#

Returns: std::move(current_).

🔗

constexpr const iterator_t<V>& base() const & noexcept;

3

#

Returns: current_.

🔗

constexpr iterator& operator++();

4

#

Effects: Equivalent to:parent_->cache_.reset();++current_;return *this;

🔗

constexpr void operator++(int);

5

#

Effects: Equivalent to: ++*this.

🔗

constexpr range_reference_t<V>& operator*() const;

6

#

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_)));

7

#

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.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<V>>;

8

#

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

1

#

Effects: Initializes end_ with ranges::end(parent.base_).

🔗

constexpr sentinel_t<V> base() const;

2

#

Returns: end_.

🔗

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

3

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;

4

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>;

5

#

Returns: x.end_ - y.current_.

25.7.35 To input view [range.to.input]

25.7.35.1 Overview [range.to.input.overview]

1

#

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]

2

#

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:

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 (simple-view); constexpr auto begin() const requires range; constexpr auto end() requires (simple-view); 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);

1

#

Effects: Initializes base_ with std::move(base).

🔗

constexpr auto begin() requires (![simple-view](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>);

2

#

Effects: Equivalent to: return iterator(ranges::begin(base_));

🔗

constexpr auto begin() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V>;

3

#

Effects: Equivalent to: return iterator(ranges::begin(base_));

🔗

constexpr auto end() requires (![simple-view](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>); constexpr auto end() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V>;

4

#

Effects: Equivalent to: return ranges::end(base_);

🔗

constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>; constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V>;

5

#

Effects: Equivalent to: return ranges::size(base_);

🔗

constexpr auto reserve_hint() requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<V>; constexpr auto reserve_hint() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<const V>;

6

#

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

1

#

Effects: Initializes current_ with std::move(current).

🔗

constexpr iterator(iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<V>, iterator_t<Base>>;

2

#

Effects: Initializes current_ with std::move(i.current_).

🔗

constexpr iterator_t<Base> base() &&;

3

#

Returns: std::move(current_).

🔗

constexpr const iterator_t<Base>& base() const & noexcept;

4

#

Returns: current_.

🔗

constexpr iterator& operator++();

5

#

Effects: Equivalent to:++current_;return *this;

🔗

constexpr void operator++(int);

6

#

Effects: Equivalent to: ++*this;

🔗

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

7

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<Base>>;

8

#

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.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<Base>, iterator_t<Base>>;

9

#

Returns: x.current_ - y.

🔗

friend constexpr range_rvalue_reference_t<Base> iter_move(const iterator& i) noexcept(noexcept(ranges::iter_move(i.current_)));

10

#

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.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<Base>>;

11

#

Effects: Equivalent to: ranges::iter_swap(x.current_, y.current_);