Files
2025-10-25 03:02:53 +03:00

9623 lines
622 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[range.adaptors]
# 25 Ranges library [[ranges]](./#ranges)
## 25.7 Range adaptors [range.adaptors]
### [25.7.1](#general) General [[range.adaptors.general]](range.adaptors.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4177)
Subclause [range.adaptors] defines [*range adaptors*](#def:range_adaptors), which are utilities that transform a
range into a view with custom behaviors[.](#general-1.sentence-1)
These
adaptors can be chained to create pipelines of range transformations that
evaluate lazily as the resulting view is iterated[.](#general-1.sentence-2)
[2](#general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4183)
Range adaptors are declared in namespace std::ranges::views[.](#general-2.sentence-1)
[3](#general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4186)
The bitwise or operator is overloaded for the purpose of creating adaptor chain
pipelines[.](#general-3.sentence-1)
The adaptors also support function call syntax with equivalent
semantics[.](#general-3.sentence-2)
[4](#general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4191)
[*Example [1](#general-example-1)*: vector<int> 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.object) Range adaptor objects [[range.adaptor.object]](range.adaptor.object)
[1](#range.adaptor.object-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4206)
A [*range adaptor closure object*](#def:range_adaptor_closure_object) is a unary function object that accepts
a range argument[.](#range.adaptor.object-1.sentence-1)
For
a range adaptor closure object C and an expression R such thatdecltype((R)) models [range](range.range#concept:range "25.4.2Ranges[range.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[.](#range.adaptor.object-1.sentence-3)
E is a perfect forwarding call wrapper ([[func.require]](func.require#term.perfect.forwarding.call.wrapper "22.10.4Requirements"))
with the following properties:
- [(1.1)](#range.adaptor.object-1.1)
Its target object is an object d of type decay_t<decltype((D))> direct-non-list-initialized with D[.](#range.adaptor.object-1.1.sentence-1)
- [(1.2)](#range.adaptor.object-1.2)
It has one bound argument entity,
an object c of type decay_t<decltype((C))> direct-non-list-initialized with C[.](#range.adaptor.object-1.2.sentence-1)
- [(1.3)](#range.adaptor.object-1.3)
Its call pattern is d(c(arg)),
where arg is the argument used in
a function call expression of E[.](#range.adaptor.object-1.3.sentence-1)
The expression C | D is well-formed if and only if
the initializations of the state entities of E are all well-formed[.](#range.adaptor.object-1.sentence-5)
[2](#range.adaptor.object-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4237)
Given an object t of type T, where
- [(2.1)](#range.adaptor.object-2.1)
t is a unary function object that accepts a range argument,
- [(2.2)](#range.adaptor.object-2.2)
T models [derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<range_adaptor_closure<T>>,
- [(2.3)](#range.adaptor.object-2.3)
T has no other base classes of type range_adaptor_closure<U> for any other type U, and
- [(2.4)](#range.adaptor.object-2.4)
T does not model [range](range.range#concept:range "25.4.2Ranges[range.range]")
then the implementation ensures
that t is a range adaptor closure object[.](#range.adaptor.object-2.sentence-1)
[3](#range.adaptor.object-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4252)
The template parameter D for range_adaptor_closure may be an incomplete type[.](#range.adaptor.object-3.sentence-1)
If an expression of type cv D is used as an operand to the | operator,D shall be complete and
model [derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<range_adaptor_closure<D>>[.](#range.adaptor.object-3.sentence-2)
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[.](#range.adaptor.object-3.sentence-3)
[4](#range.adaptor.object-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4263)
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<T> for some type T other than U, the behavior is undefined[.](#range.adaptor.object-4.sentence-1)
[5](#range.adaptor.object-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4269)
The behavior of a program
that adds a specialization for range_adaptor_closure is undefined[.](#range.adaptor.object-5.sentence-1)
[6](#range.adaptor.object-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4273)
A [*range adaptor object*](#def:range_adaptor_object) is a
customization point object ([[customization.point.object]](customization.point.object "16.3.3.3.5Customization Point Object types"))
that accepts a [viewable_range](range.refinements#concept:viewable_range "25.4.6Other range refinements[range.refinements]") as its first argument and returns a view[.](#range.adaptor.object-6.sentence-1)
[7](#range.adaptor.object-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4278)
If a range adaptor object accepts only one argument,
then it is a range adaptor closure object[.](#range.adaptor.object-7.sentence-1)
[8](#range.adaptor.object-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4282)
If a range adaptor object adaptor accepts more than one argument,
then let range be an expression
such that decltype((range)) models [viewable_range](range.refinements#concept:viewable_range "25.4.6Other range refinements[range.refinements]"),
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))>...[.](#range.adaptor.object-8.sentence-1)
The expression adaptor(args...) produces a range adaptor closure object f that is a perfect forwarding call wrapper ([[func.require]](func.require#term.perfect.forwarding.call.wrapper "22.10.4Requirements")) with the following properties:
- [(8.1)](#range.adaptor.object-8.1)
Its target object is a copy of adaptor[.](#range.adaptor.object-8.1.sentence-1)
- [(8.2)](#range.adaptor.object-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[.](#range.adaptor.object-8.2.sentence-1)
- [(8.3)](#range.adaptor.object-8.3)
Its call pattern is adaptor(r, bound_args...),
where r is the argument used in a function call expression of f[.](#range.adaptor.object-8.3.sentence-1)
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[.](#range.adaptor.object-8.sentence-3)
### [25.7.3](#range.move.wrap) Movable wrapper [[range.move.wrap]](range.move.wrap)
[1](#range.move.wrap-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4308)
Many types in this subclause are specified in terms of
an exposition-only class template *movable-box*[.](#range.move.wrap-1.sentence-1)
*movable-box*<T> behaves exactly like optional<T> with the following differences:
- [(1.1)](#range.move.wrap-1.1)
*movable-box*<T> constrains
its type parameter T with[move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13Concept move_­constructible[concept.moveconstructible]")<T> && is_object_v<T>.
- [(1.2)](#range.move.wrap-1.2)
The default
constructor of *movable-box*<T> is equivalent to:constexpr *movable-box*() noexcept(is_nothrow_default_constructible_v<T>)requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<T>: *movable-box*{in_place} {}
- [(1.3)](#range.move.wrap-1.3)
If [copyable](concepts.object#concept:copyable "18.6Object concepts[concepts.object]")<T> is not
modeled, the copy assignment operator is equivalent to:constexpr *movable-box*& operator=(const *movable-box*& that)noexcept(is_nothrow_copy_constructible_v<T>)requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<T> {if (this != addressof(that)) {if (that) emplace(*that); else reset(); }return *this;}
- [(1.4)](#range.move.wrap-1.4)
If [movable](concepts.object#concept:movable "18.6Object concepts[concepts.object]")<T> is not modeled,
the move assignment operator is equivalent to:constexpr *movable-box*& operator=(*movable-box*&& that)noexcept(is_nothrow_move_constructible_v<T>) {if (this != addressof(that)) {if (that) emplace(std::move(*that)); else reset(); }return *this;}
[2](#range.move.wrap-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4354)
*Recommended practice*:
- [(2.1)](#range.move.wrap-2.1)
If [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<T> is true,*movable-box*<T> should store only a T if either T models [copyable](concepts.object#concept:copyable "18.6Object concepts[concepts.object]"), oris_nothrow_move_constructible_v<T> && is_nothrow_copy_constructible_v<T> is true[.](#range.move.wrap-2.1.sentence-1)
- [(2.2)](#range.move.wrap-2.2)
Otherwise, *movable-box*<T> should store only a T if either T models [movable](concepts.object#concept:movable "18.6Object concepts[concepts.object]") oris_nothrow_move_constructible_v<T> is true[.](#range.move.wrap-2.2.sentence-1)
### [25.7.4](#range.nonprop.cache) Non-propagating cache [[range.nonprop.cache]](range.nonprop.cache)
[1](#range.nonprop.cache-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4371)
Some types in [range.adaptors] are specified in terms of
an exposition-only class template *non-propagating-cache*[.](#range.nonprop.cache-1.sentence-1)
*non-propagating-cache*<T> behaves exactly like optional<T> with the following differences:
- [(1.1)](#range.nonprop.cache-1.1)
*non-propagating-cache*<T> constrains its type parameter T with is_object_v<T>.
- [(1.2)](#range.nonprop.cache-1.2)
The copy constructor is equivalent to:constexpr *non-propagating-cache*(const *non-propagating-cache*&) noexcept {}
- [(1.3)](#range.nonprop.cache-1.3)
The move constructor is equivalent to:constexpr *non-propagating-cache*(*non-propagating-cache*&& other) noexcept { other.reset();}
- [(1.4)](#range.nonprop.cache-1.4)
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;}
- [(1.5)](#range.nonprop.cache-1.5)
The move assignment operator is equivalent to:constexpr *non-propagating-cache*& operator=(*non-propagating-cache*&& other) noexcept { reset();
other.reset(); return *this;}
- [(1.6)](#range.nonprop.cache-1.6)
*non-propagating-cache*<T> has an additional member function template
specified as follows:
[🔗](#range.nonprop.cache-1.6.itemdecl:1)
`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[.](#range.nonprop.cache-1.6.sentence-2)
[*Note [1](#range.nonprop.cache-note-1)*:
If *i is a prvalue of type cv T,
there is no requirement that it is movable ([[dcl.init.general]](dcl.init.general "9.5.1General"))[.](#range.nonprop.cache-1.6.sentence-3)
— *end note*]
*Effects*: Calls reset()[.](#range.nonprop.cache-1.6.sentence-4)
Then direct-non-list-initializes the contained value with *i[.](#range.nonprop.cache-1.6.sentence-5)
*Postconditions*: *this contains a value[.](#range.nonprop.cache-1.6.sentence-6)
*Returns*: A reference to the new contained value[.](#range.nonprop.cache-1.6.sentence-7)
*Throws*: Any exception thrown by the initialization of the contained value[.](#range.nonprop.cache-1.6.sentence-8)
*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[.](#range.nonprop.cache-1.6.sentence-9)
[2](#range.nonprop.cache-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4449)
[*Note [2](#range.nonprop.cache-note-2)*:
*non-propagating-cache* enables an input view
to temporarily cache values as it is iterated over[.](#range.nonprop.cache-2.sentence-1)
— *end note*]
### [25.7.5](#range.adaptor.helpers) Range adaptor helpers [[range.adaptor.helpers]](range.adaptor.helpers)
namespace std::ranges {template<class F, class Tuple>constexpr auto *tuple-transform*(F&& f, Tuple&& t) { // *exposition only*return apply([&]<class... Ts>(Ts&&... elements) {return tuple<invoke_result_t<F&, Ts>...>(invoke(f, std::forward<Ts>(elements))...); }, std::forward<Tuple>(t)); }template<class F, class Tuple>constexpr void *tuple-for-each*(F&& f, Tuple&& t) { // *exposition only* apply([&]<class... Ts>(Ts&&... elements) {(static_cast<void>(invoke(f, std::forward<Ts>(elements))), ...); }, std::forward<Tuple>(t)); }template<class T>constexpr T& *as-lvalue*(T&& t) { // *exposition only*return static_cast<T&>(t); }template<bool Const, class... Views>concept [*all-random-access*](#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]") = // *exposition only*([random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*maybe-const*<Const, Views>> && ...); template<bool Const, class... Views>concept [*all-bidirectional*](#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]") = // *exposition only*([bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*maybe-const*<Const, Views>> && ...); template<bool Const, class... Views>concept [*all-forward*](#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]") = // *exposition only*([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*maybe-const*<Const, Views>> && ...);}
### [25.7.6](#range.all) All view [[range.all]](range.all)
#### [25.7.6.1](#range.all.general) General [[range.all.general]](range.all.general)
[1](#range.all.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4494)
views::all returns a view that includes all elements of
its range argument[.](#range.all.general-1.sentence-1)
[2](#range.all.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4499)
The name views::all denotes a
range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.all.general-2.sentence-1)
Given a subexpression E, the expressionviews::all(E) is expression-equivalent to:
- [(2.1)](#range.all.general-2.1)
*decay-copy*(E) if the decayed type of E models [view](range.view#concept:view "25.4.5Views[range.view]")[.](#range.all.general-2.1.sentence-1)
- [(2.2)](#range.all.general-2.2)
Otherwise, ref_view{E} if that expression is well-formed[.](#range.all.general-2.2.sentence-1)
- [(2.3)](#range.all.general-2.3)
Otherwise, owning_view{E}[.](#range.all.general-2.3.sentence-1)
#### [25.7.6.2](#range.ref.view) Class template ref_view [[range.ref.view]](range.ref.view)
[1](#range.ref.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4515)
ref_view is a view of the elements of some other range[.](#range.ref.view-1.sentence-1)
[🔗](#lib:ref_view)
namespace std::ranges {template<[range](range.range#concept:range "25.4.2Ranges[range.range]") R>requires is_object_v<R>class ref_view : public view_interface<ref_view<R>> {private: R* *r_*; // *exposition only*public: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); constexpr R& base() const { return **r_*; }constexpr iterator_t<R> begin() const { return ranges::begin(**r_*); }constexpr sentinel_t<R> end() const { return ranges::end(**r_*); }constexpr bool empty() constrequires requires { ranges::empty(**r_*); }{ return ranges::empty(**r_*); }constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<R>{ return ranges::size(**r_*); }constexpr auto reserve_hint() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<R>{ return ranges::reserve_hint(**r_*); }constexpr auto data() const requires [contiguous_range](range.refinements#concept:contiguous_range "25.4.6Other range refinements[range.refinements]")<R>{ return ranges::data(**r_*); }}; template<class R> ref_view(R&) -> ref_view<R>;}
[🔗](#lib:ref_view,constructor)
`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](#range.ref.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4563)
*Effects*: Initializes *r_* withaddressof(static_cast<R&>(std::forward<T>(t)))[.](#range.ref.view-2.sentence-1)
[3](#range.ref.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4568)
*Remarks*: Let *FUN* denote the exposition-only functionsvoid *FUN*(R&);void *FUN*(R&&) = delete;
The expression in the [*requires-clause*](temp.pre#nt:requires-clause "13.1Preamble[temp.pre]") is equivalent to:[convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<T, R&> && requires { *FUN*(declval<T>()); }
#### [25.7.6.3](#range.owning.view) Class template owning_view [[range.owning.view]](range.owning.view)
[1](#range.owning.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4583)
owning_view is a move-only view
of the elements of some other range[.](#range.owning.view-1.sentence-1)
[🔗](#lib:owning_view)
namespace std::ranges {template<[range](range.range#concept:range "25.4.2Ranges[range.range]") R>requires [movable](concepts.object#concept:movable "18.6Object concepts[concepts.object]")<R> && (!*is-initializer-list*<R>) // see [[range.refinements]](range.refinements "25.4.6Other range refinements")class owning_view : public view_interface<owning_view<R>> {private: R *r_* = R(); // *exposition only*public: owning_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<R> = 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<R> begin() { return ranges::begin(*r_*); }constexpr sentinel_t<R> end() { return ranges::end(*r_*); }constexpr auto begin() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const R>{ return ranges::begin(*r_*); }constexpr auto end() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const R>{ 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](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<R>{ return ranges::size(*r_*); }constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const R>{ return ranges::size(*r_*); }constexpr auto reserve_hint() requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<R>{ return ranges::reserve_hint(*r_*); }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 R>{ return ranges::reserve_hint(*r_*); }constexpr auto data() requires [contiguous_range](range.refinements#concept:contiguous_range "25.4.6Other range refinements[range.refinements]")<R>{ return ranges::data(*r_*); }constexpr auto data() const requires [contiguous_range](range.refinements#concept:contiguous_range "25.4.6Other range refinements[range.refinements]")<const R>{ return ranges::data(*r_*); }};}
[🔗](#lib:owning_view,constructor)
`constexpr owning_view(R&& t);
`
[2](#range.owning.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4645)
*Effects*: Initializes *r_* with std::move(t)[.](#range.owning.view-2.sentence-1)
### [25.7.7](#range.as.rvalue) As rvalue view [[range.as.rvalue]](range.as.rvalue)
#### [25.7.7.1](#range.as.rvalue.overview) Overview [[range.as.rvalue.overview]](range.as.rvalue.overview)
[1](#range.as.rvalue.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4654)
as_rvalue_view presents a view of an underlying sequence
with the same behavior as the underlying sequence
except that its elements are rvalues[.](#range.as.rvalue.overview-1.sentence-1)
Some generic algorithms can be called with an as_rvalue_view to replace copying with moving[.](#range.as.rvalue.overview-1.sentence-2)
[2](#range.as.rvalue.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4661)
The name views::as_rvalue denotes
a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.as.rvalue.overview-2.sentence-1)
Let E be an expression and let T be decltype((E))[.](#range.as.rvalue.overview-2.sentence-2)
The expression views::as_rvalue(E) is expression-equivalent to:
- [(2.1)](#range.as.rvalue.overview-2.1)
views::all(E) ifT models [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") and[same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<range_rvalue_reference_t<T>, range_reference_t<T>> is true[.](#range.as.rvalue.overview-2.1.sentence-1)
- [(2.2)](#range.as.rvalue.overview-2.2)
Otherwise, as_rvalue_view(E)[.](#range.as.rvalue.overview-2.2.sentence-1)
[3](#range.as.rvalue.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4676)
[*Example [1](#range.as.rvalue.overview-example-1)*: vector<string> words = {"the", "quick", "brown", "fox", "ate", "a", "pterodactyl"};
vector<string> 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](#range.as.rvalue.view) Class template as_rvalue_view [[range.as.rvalue.view]](range.as.rvalue.view)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V>requires [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<V>class [as_rvalue_view](#lib:as_rvalue_view "25.7.7.2Class template as_­rvalue_­view[range.as.rvalue.view]") : public view_interface<as_rvalue_view<V>> { V *base_* = V(); // *exposition only*public: as_rvalue_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> = default; constexpr explicit as_rvalue_view(V base); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr auto begin() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>){ return move_iterator(ranges::begin(*base_*)); }constexpr auto begin() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V>{ return move_iterator(ranges::begin(*base_*)); }constexpr auto end() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>) {if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V>) {return move_iterator(ranges::end(*base_*)); } else {return move_sentinel(ranges::end(*base_*)); }}constexpr auto end() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V> {if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<const V>) {return move_iterator(ranges::end(*base_*)); } else {return move_sentinel(ranges::end(*base_*)); }}constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V> { return ranges::size(*base_*); }constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V> { 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>{ return ranges::reserve_hint(*base_*); }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>{ return ranges::reserve_hint(*base_*); }}; template<class R> as_rvalue_view(R&&) -> as_rvalue_view<views::all_t<R>>;}
[🔗](#lib:as_rvalue_view,constructor)
`constexpr explicit as_rvalue_view(V base);
`
[1](#range.as.rvalue.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4742)
*Effects*: Initializes *base_* with std::move(base)[.](#range.as.rvalue.view-1.sentence-1)
### [25.7.8](#range.filter) Filter view [[range.filter]](range.filter)
#### [25.7.8.1](#range.filter.overview) Overview [[range.filter.overview]](range.filter.overview)
[1](#range.filter.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4751)
filter_view presents a view of the elements
of an underlying sequence that satisfy a predicate[.](#range.filter.overview-1.sentence-1)
[2](#range.filter.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4755)
The name views::filter denotes a
range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.filter.overview-2.sentence-1)
Given subexpressions E and P,
the expression views::filter(E, P) is expression-equivalent tofilter_view(E, P)[.](#range.filter.overview-2.sentence-2)
[3](#range.filter.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4763)
[*Example [1](#range.filter.overview-example-1)*: vector<int> 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](#range.filter.view) Class template filter_view [[range.filter.view]](range.filter.view)
[🔗](#lib:filter_view)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [indirect_unary_predicate](indirectcallable.indirectinvocable#concept:indirect_unary_predicate "24.3.6.3Indirect callables[indirectcallable.indirectinvocable]")<iterator_t<V>> Pred>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && is_object_v<Pred>class filter_view : public view_interface<filter_view<V, Pred>> {private: V *base_* = V(); // *exposition only**movable-box*<Pred> *pred_*; // *exposition only*// [[range.filter.iterator]](#range.filter.iterator "25.7.8.3Class filter_­view::iterator"), class filter_view::*iterator*class *iterator*; // *exposition only*// [[range.filter.sentinel]](#range.filter.sentinel "25.7.8.4Class filter_­view::sentinel"), class filter_view::*sentinel*class *sentinel*; // *exposition only*public: filter_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> && [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<Pred> = default; constexpr explicit filter_view(V base, Pred pred); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr const Pred& pred() const; constexpr *iterator* begin(); constexpr auto end() {if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V>)return *iterator*{*this, ranges::end(*base_*)}; elsereturn *sentinel*{*this}; }}; template<class R, class Pred> filter_view(R&&, Pred) -> filter_view<views::all_t<R>, Pred>;}
[🔗](#lib:filter_view,constructor)
`constexpr explicit filter_view(V base, Pred pred);
`
[1](#range.filter.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4822)
*Effects*: Initializes *base_* with std::move(base) and initializes*pred_* with std::move(pred)[.](#range.filter.view-1.sentence-1)
[🔗](#lib:pred,filter_view)
`constexpr const Pred& pred() const;
`
[2](#range.filter.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4834)
*Effects*: Equivalent to: return **pred_*;
[🔗](#lib:begin,filter_view)
`constexpr iterator begin();
`
[3](#range.filter.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4845)
*Preconditions*: *pred_*.has_value() is true[.](#range.filter.view-3.sentence-1)
[4](#range.filter.view-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4849)
*Returns*: {*this, ranges::find_if(*base_*, ref(**pred_*))}[.](#range.filter.view-4.sentence-1)
[5](#range.filter.view-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4853)
*Remarks*: In order to provide the amortized constant time complexity required by
the [range](range.range#concept:range "25.4.2Ranges[range.range]") concept
when filter_view models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"),
this function caches the result within thefilter_view for use on subsequent calls[.](#range.filter.view-5.sentence-1)
#### [25.7.8.3](#range.filter.iterator) Class filter_view::*iterator* [[range.filter.iterator]](range.filter.iterator)
[🔗](#lib:filter_view::iterator)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [indirect_unary_predicate](indirectcallable.indirectinvocable#concept:indirect_unary_predicate "24.3.6.3Indirect callables[indirectcallable.indirectinvocable]")<iterator_t<V>> Pred>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && is_object_v<Pred>class filter_view<V, Pred>::*iterator* {private: iterator_t<V> *current_* = iterator_t<V>(); // *exposition only* filter_view* *parent_* = nullptr; // *exposition only*public:using iterator_concept = *see below*; using iterator_category = *see below*; // not always presentusing value_type = range_value_t<V>; using difference_type = range_difference_t<V>; *iterator*() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<iterator_t<V>> = default; constexpr *iterator*(filter_view& parent, iterator_t<V> current); constexpr const iterator_t<V>& base() const & noexcept; constexpr iterator_t<V> base() &&; constexpr range_reference_t<V> operator*() const; constexpr iterator_t<V> operator->() constrequires [*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>>; constexpr *iterator*& operator++(); constexpr void operator++(int); constexpr *iterator* operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>; constexpr *iterator*& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<V>; constexpr *iterator* operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<V>; 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>>; friend constexpr range_rvalue_reference_t<V> iter_move(const *iterator*& i)noexcept(noexcept(ranges::iter_move(i.*current_*))); friend constexpr void iter_swap(const *iterator*& x, const *iterator*& y)noexcept(noexcept(ranges::iter_swap(x.*current_*, y.*current_*)))requires [indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<V>>; };}
[1](#range.filter.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4910)
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[.](#range.filter.iterator-1.sentence-1)
[2](#range.filter.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4915)
*iterator*::iterator_concept is defined as follows:
- [(2.1)](#range.filter.iterator-2.1)
If V models [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]"), theniterator_concept denotes bidirectional_iterator_tag[.](#range.filter.iterator-2.1.sentence-1)
- [(2.2)](#range.filter.iterator-2.2)
Otherwise, if V models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"), theniterator_concept denotes forward_iterator_tag[.](#range.filter.iterator-2.2.sentence-1)
- [(2.3)](#range.filter.iterator-2.3)
Otherwise, iterator_concept denotes input_iterator_tag[.](#range.filter.iterator-2.3.sentence-1)
[3](#range.filter.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4927)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") iterator_category is defined
if and only if V models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")[.](#range.filter.iterator-3.sentence-1)
In that case,*iterator*::iterator_category is defined as follows:
- [(3.1)](#range.filter.iterator-3.1)
Let C denote the typeiterator_traits<iterator_t<V>>::iterator_category[.](#range.filter.iterator-3.1.sentence-1)
- [(3.2)](#range.filter.iterator-3.2)
If C models[derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<bidirectional_iterator_tag>,
then iterator_category denotes bidirectional_iterator_tag[.](#range.filter.iterator-3.2.sentence-1)
- [(3.3)](#range.filter.iterator-3.3)
Otherwise, if C models[derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<forward_iterator_tag>,
then iterator_category denotes forward_iterator_tag[.](#range.filter.iterator-3.3.sentence-1)
- [(3.4)](#range.filter.iterator-3.4)
Otherwise, iterator_category denotes C[.](#range.filter.iterator-3.4.sentence-1)
[🔗](#lib:filter_view::iterator,constructor)
`constexpr iterator(filter_view& parent, iterator_t<V> current);
`
[4](#range.filter.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4953)
*Effects*: Initializes *current_* with std::move(current) and*parent_* with addressof(parent)[.](#range.filter.iterator-4.sentence-1)
[🔗](#lib:base,filter_view::iterator)
`constexpr const iterator_t<V>& base() const & noexcept;
`
[5](#range.filter.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4965)
*Effects*: Equivalent to: return *current_*;
[🔗](#lib:base,filter_view::iterator_)
`constexpr iterator_t<V> base() &&;
`
[6](#range.filter.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4976)
*Effects*: Equivalent to: return std::move(*current_*);
[🔗](#lib:operator*,filter_view::iterator)
`constexpr range_reference_t<V> operator*() const;
`
[7](#range.filter.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4987)
*Effects*: Equivalent to: return **current_*;
[🔗](#lib:operator-%3e,filter_view::iterator)
`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](#range.filter.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4999)
*Effects*: Equivalent to: return *current_*;
[🔗](#lib:operator++,filter_view::iterator)
`constexpr iterator& operator++();
`
[9](#range.filter.iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5010)
*Effects*: Equivalent to:*current_* = ranges::find_if(std::move(++*current_*), ranges::end(*parent_*->*base_*),
ref(**parent_*->*pred_*));return *this;
[🔗](#lib:operator++,filter_view::iterator_)
`constexpr void operator++(int);
`
[10](#range.filter.iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5026)
*Effects*: Equivalent to ++*this[.](#range.filter.iterator-10.sentence-1)
[🔗](#lib:operator++,filter_view::iterator__)
`constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>;
`
[11](#range.filter.iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5037)
*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,filter_view::iterator)
`constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<V>;
`
[12](#range.filter.iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5053)
*Effects*: Equivalent to:do--*current_*;while (!invoke(**parent_*->*pred_*, **current_*));return *this;
[🔗](#lib:operator--,filter_view::iterator_)
`constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<V>;
`
[13](#range.filter.iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5070)
*Effects*: Equivalent to:auto tmp = *this;--*this;return tmp;
[🔗](#lib:operator==,filter_view::iterator)
`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](#range.filter.iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5087)
*Effects*: Equivalent to: return x.*current_* == y.*current_*;
[🔗](#lib:iter_move,filter_view::iterator)
`friend constexpr range_rvalue_reference_t<V> iter_move(const iterator& i)
noexcept(noexcept(ranges::iter_move(i.current_)));
`
[15](#range.filter.iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5099)
*Effects*: Equivalent to: return ranges::iter_move(i.*current_*);
[🔗](#lib:iter_swap,filter_view::iterator)
`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](#range.filter.iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5112)
*Effects*: Equivalent to ranges::iter_swap(x.*current_*, y.*current_*)[.](#range.filter.iterator-16.sentence-1)
#### [25.7.8.4](#range.filter.sentinel) Class filter_view::*sentinel* [[range.filter.sentinel]](range.filter.sentinel)
[🔗](#lib:filter_view::sentinel)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [indirect_unary_predicate](indirectcallable.indirectinvocable#concept:indirect_unary_predicate "24.3.6.3Indirect callables[indirectcallable.indirectinvocable]")<iterator_t<V>> Pred>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && is_object_v<Pred>class filter_view<V, Pred>::*sentinel* {private: sentinel_t<V> *end_* = sentinel_t<V>(); // *exposition only*public:*sentinel*() = default; constexpr explicit *sentinel*(filter_view& parent); constexpr sentinel_t<V> base() const; friend constexpr bool operator==(const *iterator*& x, const *sentinel*& y); };}
[🔗](#lib:filter_view::sentinel,constructor)
`constexpr explicit sentinel(filter_view& parent);
`
[1](#range.filter.sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5146)
*Effects*: Initializes *end_* with ranges::end(parent.*base_*)[.](#range.filter.sentinel-1.sentence-1)
[🔗](#lib:base,filter_view::sentinel)
`constexpr sentinel_t<V> base() const;
`
[2](#range.filter.sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5157)
*Effects*: Equivalent to: return *end_*;
[🔗](#lib:operator==,filter_view::sentinel)
`friend constexpr bool operator==(const iterator& x, const sentinel& y);
`
[3](#range.filter.sentinel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5168)
*Effects*: Equivalent to: return x.*current_* == y.*end_*;
### [25.7.9](#range.transform) Transform view [[range.transform]](range.transform)
#### [25.7.9.1](#range.transform.overview) Overview [[range.transform.overview]](range.transform.overview)
[1](#range.transform.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5177)
transform_view presents
a view of an underlying sequence after
applying a transformation function to each element[.](#range.transform.overview-1.sentence-1)
[2](#range.transform.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5182)
The name views::transform denotes a
range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.transform.overview-2.sentence-1)
Given subexpressions E and F, the expressionviews::transform(E, F) is expression-equivalent totransform_view(E, F)[.](#range.transform.overview-2.sentence-2)
[3](#range.transform.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5190)
[*Example [1](#range.transform.overview-example-1)*: vector<int> 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](#range.transform.view) Class template transform_view [[range.transform.view]](range.transform.view)
[🔗](#lib:transform_view)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13Concept move_­constructible[concept.moveconstructible]") F>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && is_object_v<F> &&[regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<F&, range_reference_t<V>> &&[*can-reference*](iterator.synopsis#concept:can-reference "24.2Header <iterator>&nbsp;synopsis[iterator.synopsis]")<invoke_result_t<F&, range_reference_t<V>>>class transform_view : public view_interface<transform_view<V, F>> {private:// [[range.transform.iterator]](#range.transform.iterator "25.7.9.3Class template transform_­view::iterator"), class template transform_view::*iterator*template<bool> struct *iterator*; // *exposition only*// [[range.transform.sentinel]](#range.transform.sentinel "25.7.9.4Class template transform_­view::sentinel"), class template transform_view::*sentinel*template<bool> struct *sentinel*; // *exposition only* V *base_* = V(); // *exposition only**movable-box*<F> *fun_*; // *exposition only*public: transform_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> && [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<F> = default; constexpr explicit transform_view(V base, F fun); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr *iterator*<false> begin(); constexpr *iterator*<true> begin() constrequires [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>>; constexpr *sentinel*<false> end(); constexpr *iterator*<false> end() requires [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V>; constexpr *sentinel*<true> end() constrequires [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>>; constexpr *iterator*<true> end() constrequires [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>>; constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V> { return ranges::size(*base_*); }constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V>{ 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>{ return ranges::reserve_hint(*base_*); }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>{ return ranges::reserve_hint(*base_*); }}; template<class R, class F> transform_view(R&&, F) -> transform_view<views::all_t<R>, F>;}
[🔗](#lib:transform_view,constructor)
`constexpr explicit transform_view(V base, F fun);
`
[1](#range.transform.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5264)
*Effects*: Initializes *base_* with std::move(base) and*fun_* with std::move(fun)[.](#range.transform.view-1.sentence-1)
[🔗](#lib:begin,transform_view)
`constexpr iterator<false> begin();
`
[2](#range.transform.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5276)
*Effects*: Equivalent to:return *iterator*<false>{*this, ranges::begin(*base_*)};
[🔗](#lib:begin,transform_view_)
`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](#range.transform.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5292)
*Effects*: Equivalent to:return *iterator*<true>{*this, ranges::begin(*base_*)};
[🔗](#lib:end,transform_view)
`constexpr sentinel<false> end();
`
[4](#range.transform.view-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5306)
*Effects*: Equivalent to:return *sentinel*<false>{ranges::end(*base_*)};
[🔗](#lib:end,transform_view_)
`constexpr iterator<false> end() requires [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V>;
`
[5](#range.transform.view-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5320)
*Effects*: Equivalent to:return *iterator*<false>{*this, ranges::end(*base_*)};
[🔗](#lib:end,transform_view__)
`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](#range.transform.view-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5336)
*Effects*: Equivalent to:return *sentinel*<true>{ranges::end(*base_*)};
[🔗](#lib:end,transform_view___)
`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](#range.transform.view-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5352)
*Effects*: Equivalent to:return *iterator*<true>{*this, ranges::end(*base_*)};
#### [25.7.9.3](#range.transform.iterator) Class template transform_view::*iterator* [[range.transform.iterator]](range.transform.iterator)
[🔗](#lib:transform_view::iterator)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13Concept move_­constructible[concept.moveconstructible]") F>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && is_object_v<F> &&[regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<F&, range_reference_t<V>> &&[*can-reference*](iterator.synopsis#concept:can-reference "24.2Header <iterator>&nbsp;synopsis[iterator.synopsis]")<invoke_result_t<F&, range_reference_t<V>>>template<bool Const>class transform_view<V, F>::*iterator* {private:using *Parent* = *maybe-const*<Const, transform_view>; // *exposition only*using *Base* = *maybe-const*<Const, V>; // *exposition only* iterator_t<*Base*> *current_* = iterator_t<*Base*>(); // *exposition only**Parent** *parent_* = nullptr; // *exposition only*public: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](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<iterator_t<*Base*>> = default; constexpr *iterator*(*Parent*& parent, iterator_t<*Base*> 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*>>; 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](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator* operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator+=(difference_type n)requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator-=(difference_type n)requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr decltype(auto) operator[](difference_type n) constrequires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*> {return invoke(**parent_*->*fun_*, *current_*[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<*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 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]")<iterator_t<*Base*>>; 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*>; 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 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*>>; };}
[1](#range.transform.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5441)
*iterator*::iterator_concept is defined as follows:
- [(1.1)](#range.transform.iterator-1.1)
If *Base* models [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]"), theniterator_concept denotes random_access_iterator_tag[.](#range.transform.iterator-1.1.sentence-1)
- [(1.2)](#range.transform.iterator-1.2)
Otherwise, if *Base* models [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]"), theniterator_concept denotes bidirectional_iterator_tag[.](#range.transform.iterator-1.2.sentence-1)
- [(1.3)](#range.transform.iterator-1.3)
Otherwise, if *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"), theniterator_concept denotes forward_iterator_tag[.](#range.transform.iterator-1.3.sentence-1)
- [(1.4)](#range.transform.iterator-1.4)
Otherwise, iterator_concept denotes input_iterator_tag[.](#range.transform.iterator-1.4.sentence-1)
[2](#range.transform.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5456)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") iterator_category is defined
if and only if *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")[.](#range.transform.iterator-2.sentence-1)
In that case,*iterator*::iterator_category is defined as follows:
Let C denote the typeiterator_traits<iterator_t<*Base*>>::iterator_category[.](#range.transform.iterator-2.sentence-2)
- [(2.1)](#range.transform.iterator-2.1)
If is_reference_v<invoke_result_t<*maybe-const*<Const, F>&, range_reference_t<*Base*>>> is true, then
* [(2.1.1)](#range.transform.iterator-2.1.1)
if C models [derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<contiguous_iterator_tag>,iterator_category denotes random_access_iterator_tag;
* [(2.1.2)](#range.transform.iterator-2.1.2)
otherwise,iterator_category denotes C[.](#range.transform.iterator-2.1.sentence-1)
- [(2.2)](#range.transform.iterator-2.2)
Otherwise, iterator_category denotes input_iterator_tag[.](#range.transform.iterator-2.2.sentence-1)
[🔗](#lib:iterator,transform_view::iterator)
`constexpr iterator(Parent& parent, iterator_t<Base> current);
`
[3](#range.transform.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5487)
*Effects*: Initializes *current_* with std::move(current) and*parent_* with addressof(parent)[.](#range.transform.iterator-3.sentence-1)
[🔗](#lib:transform_view::iterator,constructor)
`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](#range.transform.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5500)
*Effects*: Initializes *current_* with std::move(i.*current_*) and*parent_* with i.*parent_*[.](#range.transform.iterator-4.sentence-1)
[🔗](#lib:base,transform_view::iterator)
`constexpr const iterator_t<Base>& base() const & noexcept;
`
[5](#range.transform.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5512)
*Effects*: Equivalent to: return *current_*;
[🔗](#lib:base,transform_view::iterator_)
`constexpr iterator_t<Base> base() &&;
`
[6](#range.transform.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5523)
*Effects*: Equivalent to: return std::move(*current_*);
[🔗](#lib:operator++,transform_view::iterator)
`constexpr iterator& operator++();
`
[7](#range.transform.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5534)
*Effects*: Equivalent to:++*current_*;return *this;
[🔗](#lib:operator++,transform_view::iterator_)
`constexpr void operator++(int);
`
[8](#range.transform.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5549)
*Effects*: Equivalent to ++*current_*[.](#range.transform.iterator-8.sentence-1)
[🔗](#lib:operator++,transform_view::iterator__)
`constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[9](#range.transform.iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5560)
*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,transform_view::iterator)
`constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[10](#range.transform.iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5576)
*Effects*: Equivalent to:--*current_*;return *this;
[🔗](#lib:operator--,transform_view::iterator_)
`constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[11](#range.transform.iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5591)
*Effects*: Equivalent to:auto tmp = *this;--*this;return tmp;
[🔗](#lib:operator+=,transform_view::iterator)
`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](#range.transform.iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5608)
*Effects*: Equivalent to:*current_* += n;return *this;
[🔗](#lib:operator-=,transform_view::iterator)
`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](#range.transform.iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5624)
*Effects*: Equivalent to:*current_* -= n;return *this;
[🔗](#lib:operator==,transform_view::iterator)
`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](#range.transform.iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5640)
*Effects*: Equivalent to: return x.*current_* == y.*current_*;
[🔗](#lib:operator%3c,transform_view::iterator)
`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](#range.transform.iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5652)
*Effects*: Equivalent to: return x.*current_* < y.*current_*;
[🔗](#lib:operator%3e,transform_view::iterator)
`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](#range.transform.iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5664)
*Effects*: Equivalent to: return y < x;
[🔗](#lib:operator%3c=,transform_view::iterator)
`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](#range.transform.iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5676)
*Effects*: Equivalent to: return !(y < x);
[🔗](#lib:operator%3e=,transform_view::iterator)
`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](#range.transform.iterator-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5688)
*Effects*: Equivalent to: return !(x < y);
[🔗](#lib:operator%3c=%3e,transform_view::iterator)
`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](#range.transform.iterator-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5700)
*Effects*: Equivalent to: return x.*current_* <=> y.*current_*;
[🔗](#lib:operator+,transform_view::iterator)
`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](#range.transform.iterator-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5714)
*Effects*: Equivalent to: return *iterator*{*i.*parent_*, i.*current_* + n};
[🔗](#lib:operator-,transform_view::iterator)
`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](#range.transform.iterator-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5726)
*Effects*: Equivalent to: return *iterator*{*i.*parent_*, i.*current_* - n};
[🔗](#lib:operator-,transform_view::iterator_)
`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](#range.transform.iterator-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5738)
*Effects*: Equivalent to: return x.*current_* - y.*current_*;
#### [25.7.9.4](#range.transform.sentinel) Class template transform_view::*sentinel* [[range.transform.sentinel]](range.transform.sentinel)
[🔗](#lib:transform_view::sentinel)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13Concept move_­constructible[concept.moveconstructible]") F>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && is_object_v<F> &&[regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<F&, range_reference_t<V>> &&[*can-reference*](iterator.synopsis#concept:can-reference "24.2Header <iterator>&nbsp;synopsis[iterator.synopsis]")<invoke_result_t<F&, range_reference_t<V>>>template<bool Const>class transform_view<V, F>::*sentinel* {private:using *Parent* = *maybe-const*<Const, transform_view>; // *exposition only*using *Base* = *maybe-const*<Const, V>; // *exposition only* sentinel_t<*Base*> *end_* = sentinel_t<*Base*>(); // *exposition only*public:*sentinel*() = default; constexpr explicit *sentinel*(sentinel_t<*Base*> end); constexpr *sentinel*(*sentinel*<!Const> i)requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<*Base*>>; constexpr sentinel_t<*Base*> base() const; 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); 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); 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); };}
[🔗](#lib:transform_view::sentinel,constructor)
`constexpr explicit sentinel(sentinel_t<Base> end);
`
[1](#range.transform.sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5791)
*Effects*: Initializes *end_* with end[.](#range.transform.sentinel-1.sentence-1)
[🔗](#lib:transform_view::sentinel,constructor_)
`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](#range.transform.sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5803)
*Effects*: Initializes *end_* with std::move(i.*end_*)[.](#range.transform.sentinel-2.sentence-1)
[🔗](#lib:base,transform_view::sentinel)
`constexpr sentinel_t<Base> base() const;
`
[3](#range.transform.sentinel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5814)
*Effects*: Equivalent to: return *end_*;
[🔗](#lib:operator==,transform_view::sentinel)
`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](#range.transform.sentinel-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5827)
*Effects*: Equivalent to: return x.*current_* == y.*end_*;
[🔗](#lib:operator-,transform_view::sentinel)
`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](#range.transform.sentinel-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5841)
*Effects*: Equivalent to: return x.*current_* - y.*end_*;
[🔗](#lib:operator-,transform_view::sentinel_)
`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](#range.transform.sentinel-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5855)
*Effects*: Equivalent to: return y.*end_* - x.*current_*;
### [25.7.10](#range.take) Take view [[range.take]](range.take)
#### [25.7.10.1](#range.take.overview) Overview [[range.take.overview]](range.take.overview)
[1](#range.take.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5864)
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[.](#range.take.overview-1.sentence-1)
[2](#range.take.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5869)
The name views::take denotes a
range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.take.overview-2.sentence-1)
Let E and F be expressions,
let T be remove_cvref_t<decltype((E))>, and
let D be range_difference_t<decltype((E))>[.](#range.take.overview-2.sentence-2)
If decltype((F)) does not model[convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<D>,views::take(E, F) is ill-formed[.](#range.take.overview-2.sentence-3)
Otherwise, the expression views::take(E, F) is expression-equivalent to:
- [(2.1)](#range.take.overview-2.1)
If T is a specialization
of empty_view ([[range.empty.view]](range.empty.view "25.6.2.2Class template empty_­view")),
then ((void)F, *decay-copy*(E)),
except that the evaluations of E and F are indeterminately sequenced[.](#range.take.overview-2.1.sentence-1)
- [(2.2)](#range.take.overview-2.2)
Otherwise, if T models[random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]") and [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]") and is a specialization ofspan ([[views.span]](views.span "23.7.2.2Class template span")),basic_string_view ([[string.view]](string.view "27.3String view classes")), orsubrange ([[range.subrange]](range.subrange "25.5.4Sub-ranges")),
thenU(ranges::begin(E),
ranges::begin(E) + std::min<D>(ranges::distance(E), F)),
except that E is evaluated only once,
where U is a type determined as follows:
* [(2.2.1)](#range.take.overview-2.2.1)
if T is a specialization of span,
then U is span<typename T::element_type>;
* [(2.2.2)](#range.take.overview-2.2.2)
otherwise, if T is a specialization of basic_string_view,
then U is T;
* [(2.2.3)](#range.take.overview-2.2.3)
otherwise, T is a specialization of subrange, andU is subrange<iterator_t<T>>;
- [(2.3)](#range.take.overview-2.3)
otherwise, if T is
a specialization of iota_view ([[range.iota.view]](range.iota.view "25.6.4.2Class template iota_­view"))
that models [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]") and [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]"),
theniota_view(*ranges::begin(E),*(ranges::begin(E) + std::min<D>(ranges::distance(E), F))),
except that E is evaluated only once[.](#range.take.overview-2.3.sentence-1)
- [(2.4)](#range.take.overview-2.4)
Otherwise, if T is
a specialization of repeat_view ([[range.repeat.view]](range.repeat.view "25.6.5.2Class template repeat_­view")):
* [(2.4.1)](#range.take.overview-2.4.1)
if T models [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]"),
thenviews::repeat(*E.*value_*, std::min<D>(ranges::distance(E), F)) except that E is evaluated only once;
* [(2.4.2)](#range.take.overview-2.4.2)
otherwise, views::repeat(*E.*value_*, static_cast<D>(F))[.](#range.take.overview-2.4.sentence-1)
- [(2.5)](#range.take.overview-2.5)
Otherwise, take_view(E, F)[.](#range.take.overview-2.5.sentence-1)
[3](#range.take.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5938)
[*Example [1](#range.take.overview-example-1)*: vector<int> 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](#range.take.view) Class template take_view [[range.take.view]](range.take.view)
[🔗](#lib:take_view)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V>class take_view : public view_interface<take_view<V>> {private: V *base_* = V(); // *exposition only* range_difference_t<V> *count_* = 0; // *exposition only*// [[range.take.sentinel]](#range.take.sentinel "25.7.10.3Class template take_­view::sentinel"), class template take_view::*sentinel*template<bool> class *sentinel*; // *exposition only*public: take_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> = default; constexpr explicit take_view(V base, range_difference_t<V> count); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr auto begin() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>) {if constexpr ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>) {if constexpr ([random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<V>) {return ranges::begin(*base_*); } else {auto sz = range_difference_t<V>(size()); return counted_iterator(ranges::begin(*base_*), sz); }} else if constexpr ([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>>) {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](range.range#concept:range "25.4.2Ranges[range.range]")<const V> {if constexpr ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V>) {if constexpr ([random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<const V>) {return ranges::begin(*base_*); } else {auto sz = range_difference_t<const V>(size()); return counted_iterator(ranges::begin(*base_*), sz); }} else if constexpr ([sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<const V>, iterator_t<const V>>) {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*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>) {if constexpr ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>) {if constexpr ([random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<V>)return ranges::begin(*base_*) + range_difference_t<V>(size()); elsereturn default_sentinel; } else if constexpr ([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>>) {return default_sentinel; } else {return *sentinel*<false>{ranges::end(*base_*)}; }}constexpr auto end() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V> {if constexpr ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V>) {if constexpr ([random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<const V>)return ranges::begin(*base_*) + range_difference_t<const V>(size()); elsereturn default_sentinel; } else if constexpr ([sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<const V>, iterator_t<const V>>) {return default_sentinel; } else {return *sentinel*<true>{ranges::end(*base_*)}; }}constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V> {auto n = ranges::size(*base_*); return ranges::min(n, static_cast<decltype(n)>(*count_*)); }constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V> {auto n = ranges::size(*base_*); return ranges::min(n, static_cast<decltype(n)>(*count_*)); }constexpr auto reserve_hint() {if constexpr ([approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<V>) {auto n = static_cast<range_difference_t<V>>(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](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<const V>) {auto n = static_cast<range_difference_t<const V>>(ranges::reserve_hint(*base_*)); return *to-unsigned-like*(ranges::min(n, *count_*)); }return *to-unsigned-like*(*count_*); }}; template<class R> take_view(R&&, range_difference_t<R>)-> take_view<views::all_t<R>>;}
[🔗](#lib:take_view,constructor)
`constexpr explicit take_view(V base, range_difference_t<V> count);
`
[1](#range.take.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6071)
*Preconditions*: count >= 0 is true[.](#range.take.view-1.sentence-1)
[2](#range.take.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6075)
*Effects*: Initializes *base_* with std::move(base) and*count_* with count[.](#range.take.view-2.sentence-1)
#### [25.7.10.3](#range.take.sentinel) Class template take_view::*sentinel* [[range.take.sentinel]](range.take.sentinel)
[🔗](#lib:take_view::sentinel)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V>template<bool Const>class take_view<V>::*sentinel* {private:using *Base* = *maybe-const*<Const, V>; // *exposition only*template<bool OtherConst>using *CI* = counted_iterator<iterator_t<*maybe-const*<OtherConst, V>>>; // *exposition only* sentinel_t<*Base*> *end_* = sentinel_t<*Base*>(); // *exposition only*public:*sentinel*() = default; constexpr explicit *sentinel*(sentinel_t<*Base*> end); constexpr *sentinel*(*sentinel*<!Const> s)requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<*Base*>>; constexpr sentinel_t<*Base*> base() const; friend constexpr bool operator==(const *CI*<Const>& y, const *sentinel*& x); template<bool OtherConst = !Const>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 *CI*<OtherConst>& y, const *sentinel*& x); };}
[🔗](#lib:take_view::sentinel,constructor)
`constexpr explicit sentinel(sentinel_t<Base> end);
`
[1](#range.take.sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6118)
*Effects*: Initializes *end_* with end[.](#range.take.sentinel-1.sentence-1)
[🔗](#lib:take_view::sentinel,constructor_)
`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](#range.take.sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6130)
*Effects*: Initializes *end_* with std::move(s.*end_*)[.](#range.take.sentinel-2.sentence-1)
[🔗](#lib:base,take_view::sentinel)
`constexpr sentinel_t<Base> base() const;
`
[3](#range.take.sentinel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6141)
*Effects*: Equivalent to: return *end_*;
[🔗](#lib:operator==,take_view::sentinel)
`friend constexpr bool operator==(const CI<Const>& y, const sentinel& x);
template<bool OtherConst = !Const>
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 CI<OtherConst>& y, const sentinel& x);
`
[4](#range.take.sentinel-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6156)
*Effects*: Equivalent to:return y.count() == 0 || y.base() == x.*end_*;
### [25.7.11](#range.take.while) Take while view [[range.take.while]](range.take.while)
#### [25.7.11.1](#range.take.while.overview) Overview [[range.take.while.overview]](range.take.while.overview)
[1](#range.take.while.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6166)
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))[.](#range.take.while.overview-1.sentence-1)
[2](#range.take.while.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6172)
The name views::take_while denotes
a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.take.while.overview-2.sentence-1)
Given subexpressions E and F,
the expression views::take_while(E, F) is expression-equivalent to take_while_view(E, F)[.](#range.take.while.overview-2.sentence-2)
[3](#range.take.while.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6180)
[*Example [1](#range.take.while.overview-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<int>(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](#range.take.while.view) Class template take_while_view [[range.take.while.view]](range.take.while.view)
[🔗](#lib:take_while_view)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V, class Pred>requires [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<V> && is_object_v<Pred> &&[indirect_unary_predicate](indirectcallable.indirectinvocable#concept:indirect_unary_predicate "24.3.6.3Indirect callables[indirectcallable.indirectinvocable]")<const Pred, iterator_t<V>>class take_while_view : public view_interface<take_while_view<V, Pred>> {// [[range.take.while.sentinel]](#range.take.while.sentinel "25.7.11.3Class template take_­while_­view::sentinel"), class template take_while_view::*sentinel*template<bool> class *sentinel*; // *exposition only* V *base_* = V(); // *exposition only**movable-box*<Pred> *pred_*; // *exposition only*public: take_while_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> && [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<Pred> = default; constexpr explicit take_while_view(V base, Pred pred); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr const Pred& pred() const; constexpr auto begin() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>){ return ranges::begin(*base_*); }constexpr auto begin() constrequires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V> &&[indirect_unary_predicate](indirectcallable.indirectinvocable#concept:indirect_unary_predicate "24.3.6.3Indirect callables[indirectcallable.indirectinvocable]")<const Pred, iterator_t<const V>>{ return ranges::begin(*base_*); }constexpr auto end() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>){ return *sentinel*<false>(ranges::end(*base_*), addressof(**pred_*)); }constexpr auto end() constrequires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V> &&[indirect_unary_predicate](indirectcallable.indirectinvocable#concept:indirect_unary_predicate "24.3.6.3Indirect callables[indirectcallable.indirectinvocable]")<const Pred, iterator_t<const V>>{ return *sentinel*<true>(ranges::end(*base_*), addressof(**pred_*)); }}; template<class R, class Pred> take_while_view(R&&, Pred) -> take_while_view<views::all_t<R>, Pred>;}
[🔗](#lib:take_while_view,constructor)
`constexpr explicit take_while_view(V base, Pred pred);
`
[1](#range.take.while.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6250)
*Effects*: Initializes *base_* with std::move(base) and*pred_* with std::move(pred)[.](#range.take.while.view-1.sentence-1)
[🔗](#lib:pred,take_while_view)
`constexpr const Pred& pred() const;
`
[2](#range.take.while.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6262)
*Effects*: Equivalent to: return **pred_*;
#### [25.7.11.3](#range.take.while.sentinel) Class template take_while_view::*sentinel* [[range.take.while.sentinel]](range.take.while.sentinel)
[🔗](#lib:take_while_view::sentinel)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V, class Pred>requires [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<V> && is_object_v<Pred> &&[indirect_unary_predicate](indirectcallable.indirectinvocable#concept:indirect_unary_predicate "24.3.6.3Indirect callables[indirectcallable.indirectinvocable]")<const Pred, iterator_t<V>>template<bool Const>class take_while_view<V, Pred>::*sentinel* {using *Base* = *maybe-const*<Const, V>; // *exposition only* sentinel_t<*Base*> *end_* = sentinel_t<*Base*>(); // *exposition only*const Pred* *pred_* = nullptr; // *exposition only*public:*sentinel*() = default; constexpr explicit *sentinel*(sentinel_t<*Base*> end, const Pred* 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*>>; constexpr sentinel_t<*Base*> base() const { return *end_*; }friend constexpr bool operator==(const iterator_t<*Base*>& x, const *sentinel*& y); template<bool OtherConst = !Const>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_t<*maybe-const*<OtherConst, V>>& x, const *sentinel*& y); };}
[🔗](#lib:take_while_view::sentinel,constructor)
`constexpr explicit sentinel(sentinel_t<Base> end, const Pred* pred);
`
[1](#range.take.while.sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6306)
*Effects*: Initializes *end_* with end and *pred_* with pred[.](#range.take.while.sentinel-1.sentence-1)
[🔗](#lib:take_while_view::sentinel,constructor_)
`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](#range.take.while.sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6318)
*Effects*: Initializes *end_* with std::move(s.*end_*) and*pred_* with s.*pred_*[.](#range.take.while.sentinel-2.sentence-1)
[🔗](#lib:operator==,take_while_view::sentinel)
`friend constexpr bool operator==(const iterator_t<Base>& x, const sentinel& y);
template<bool OtherConst = !Const>
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_t<maybe-const<OtherConst, V>>& x,
const sentinel& y);
`
[3](#range.take.while.sentinel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6335)
*Effects*: Equivalent to:return y.*end_* == x || !invoke(*y.*pred_*, *x);
### [25.7.12](#range.drop) Drop view [[range.drop]](range.drop)
#### [25.7.12.1](#range.drop.overview) Overview [[range.drop.overview]](range.drop.overview)
[1](#range.drop.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6345)
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[.](#range.drop.overview-1.sentence-1)
[2](#range.drop.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6350)
The name views::drop denotes
a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.drop.overview-2.sentence-1)
Let E and F be expressions,
let T be remove_cvref_t<decltype((E))>, and
let D be range_difference_t<decltype((E))>[.](#range.drop.overview-2.sentence-2)
If decltype((F)) does not model[convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<D>,views::drop(E, F) is ill-formed[.](#range.drop.overview-2.sentence-3)
Otherwise, the expression views::drop(E, F) is expression-equivalent to:
- [(2.1)](#range.drop.overview-2.1)
If T is a specialization ofempty_view ([[range.empty.view]](range.empty.view "25.6.2.2Class template empty_­view")),
then ((void)F, *decay-copy*(E)),
except that the evaluations of E and F are indeterminately sequenced[.](#range.drop.overview-2.1.sentence-1)
- [(2.2)](#range.drop.overview-2.2)
Otherwise, if T models[random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]") and [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]") and is
* [(2.2.1)](#range.drop.overview-2.2.1)
a specialization of span ([[views.span]](views.span "23.7.2.2Class template span")),
* [(2.2.2)](#range.drop.overview-2.2.2)
a specialization of basic_string_view ([[string.view]](string.view "27.3String view classes")),
* [(2.2.3)](#range.drop.overview-2.2.3)
a specialization of iota_view ([[range.iota.view]](range.iota.view "25.6.4.2Class template iota_­view")), or
* [(2.2.4)](#range.drop.overview-2.2.4)
a specialization of subrange ([[range.subrange]](range.subrange "25.5.4Sub-ranges"))
where T::*StoreSize* is false,
then U(ranges::begin(E) + std::min<D>(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[.](#range.drop.overview-2.2.sentence-1)
- [(2.3)](#range.drop.overview-2.3)
Otherwise,
if T is
a specialization of subrange that models [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]") and [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]"),
thenT(ranges::begin(E) + std::min<D>(ranges::distance(E), F), ranges::end(E),*to-unsigned-like*(ranges::distance(E) - std::min<D>(ranges::distance(E), F))),
except that E and F are each evaluated only once[.](#range.drop.overview-2.3.sentence-1)
- [(2.4)](#range.drop.overview-2.4)
Otherwise, if T is
a specialization of repeat_view ([[range.repeat.view]](range.repeat.view "25.6.5.2Class template repeat_­view")):
* [(2.4.1)](#range.drop.overview-2.4.1)
if T models [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]"),
thenviews::repeat(*E.*value_*, ranges::distance(E) - std::min<D>(ranges::distance(E), F)) except that E is evaluated only once;
* [(2.4.2)](#range.drop.overview-2.4.2)
otherwise, ((void)F, *decay-copy*(E)),
except that the evaluations of E and F are indeterminately sequenced[.](#range.drop.overview-2.4.sentence-1)
- [(2.5)](#range.drop.overview-2.5)
Otherwise, drop_view(E, F)[.](#range.drop.overview-2.5.sentence-1)
[3](#range.drop.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6417)
[*Example [1](#range.drop.overview-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](#range.drop.view) Class template drop_view [[range.drop.view]](range.drop.view)
[🔗](#lib:drop_view)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V>class drop_view : public view_interface<drop_view<V>> {public: drop_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> = default; constexpr explicit drop_view(V base, range_difference_t<V> count); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }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() constrequires [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 end() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>){ return ranges::end(*base_*); }constexpr auto end() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V>{ return ranges::end(*base_*); }constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V> {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](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V> {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](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<V> {const auto s = static_cast<range_difference_t<V>>(ranges::reserve_hint(*base_*)); return *to-unsigned-like*(s < *count_* ? 0 : s - *count_*); }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> {const auto s = static_cast<range_difference_t<const V>>(ranges::reserve_hint(*base_*)); return *to-unsigned-like*(s < *count_* ? 0 : s - *count_*); }private: V *base_* = V(); // *exposition only* range_difference_t<V> *count_* = 0; // *exposition only*}; template<class R> drop_view(R&&, range_difference_t<R>) -> drop_view<views::all_t<R>>;}
[🔗](#lib:drop_view,constructor)
`constexpr explicit drop_view(V base, range_difference_t<V> count);
`
[1](#range.drop.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6494)
*Preconditions*: count >= 0 is true[.](#range.drop.view-1.sentence-1)
[2](#range.drop.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6498)
*Effects*: Initializes *base_* with std::move(base) and*count_* with count[.](#range.drop.view-2.sentence-1)
[🔗](#lib:begin,drop_view)
`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](#range.drop.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6514)
*Returns*: ranges::next(ranges::begin(*base_*), *count_*, ranges::end(*base_*))[.](#range.drop.view-3.sentence-1)
[4](#range.drop.view-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6518)
*Remarks*: In order to provide the amortized constant-time complexity required
by the [range](range.range#concept:range "25.4.2Ranges[range.range]") concept
when drop_view models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"),
the first overload caches the result within the drop_view for use on subsequent calls[.](#range.drop.view-4.sentence-1)
[*Note [1](#range.drop.view-note-1)*:
Without this,
applying a reverse_view over a drop_view would have quadratic iteration complexity[.](#range.drop.view-4.sentence-2)
— *end note*]
### [25.7.13](#range.drop.while) Drop while view [[range.drop.while]](range.drop.while)
#### [25.7.13.1](#range.drop.while.overview) Overview [[range.drop.while.overview]](range.drop.while.overview)
[1](#range.drop.while.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6536)
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))[.](#range.drop.while.overview-1.sentence-1)
[2](#range.drop.while.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6541)
The name views::drop_while denotes a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.drop.while.overview-2.sentence-1)
Given subexpressions E and F,
the expression views::drop_while(E, F) is expression-equivalent to drop_while_view(E, F)[.](#range.drop.while.overview-2.sentence-2)
[3](#range.drop.while.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6549)
[*Example [1](#range.drop.while.overview-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](#range.drop.while.view) Class template drop_while_view [[range.drop.while.view]](range.drop.while.view)
[🔗](#lib:drop_while_view)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V, class Pred>requires [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<V> && is_object_v<Pred> &&[indirect_unary_predicate](indirectcallable.indirectinvocable#concept:indirect_unary_predicate "24.3.6.3Indirect callables[indirectcallable.indirectinvocable]")<const Pred, iterator_t<V>>class drop_while_view : public view_interface<drop_while_view<V, Pred>> {public: drop_while_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> && [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<Pred> = default; constexpr explicit drop_while_view(V base, Pred pred); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { 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> *pred_*; // *exposition only*}; template<class R, class Pred> drop_while_view(R&&, Pred) -> drop_while_view<views::all_t<R>, Pred>;}
[🔗](#lib:drop_while_view,constructor)
`constexpr explicit drop_while_view(V base, Pred pred);
`
[1](#range.drop.while.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6601)
*Effects*: Initializes *base_* with std::move(base) and*pred_* with std::move(pred)[.](#range.drop.while.view-1.sentence-1)
[🔗](#lib:pred,drop_while_view)
`constexpr const Pred& pred() const;
`
[2](#range.drop.while.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6613)
*Effects*: Equivalent to: return **pred_*;
[🔗](#lib:begin,drop_while_view)
`constexpr auto begin();
`
[3](#range.drop.while.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6624)
*Preconditions*: *pred_*.has_value() is true[.](#range.drop.while.view-3.sentence-1)
[4](#range.drop.while.view-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6628)
*Returns*: ranges::find_if_not(*base_*, cref(**pred_*))[.](#range.drop.while.view-4.sentence-1)
[5](#range.drop.while.view-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6632)
*Remarks*: In order to provide the amortized constant-time complexity
required by the [range](range.range#concept:range "25.4.2Ranges[range.range]") concept
when drop_while_view models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"),
the first call caches the result within the drop_while_view for use on subsequent calls[.](#range.drop.while.view-5.sentence-1)
[*Note [1](#range.drop.while.view-note-1)*:
Without this,
applying a reverse_view over a drop_while_view would have quadratic iteration complexity[.](#range.drop.while.view-5.sentence-2)
— *end note*]
### [25.7.14](#range.join) Join view [[range.join]](range.join)
#### [25.7.14.1](#range.join.overview) Overview [[range.join.overview]](range.join.overview)
[1](#range.join.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6650)
join_view flattens a view of ranges into a view[.](#range.join.overview-1.sentence-1)
[2](#range.join.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6653)
The name views::join denotes a
range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.join.overview-2.sentence-1)
Given a subexpression E, the expressionviews::join(E) is expression-equivalent tojoin_view<views::all_t<decltype((E))>>{E}[.](#range.join.overview-2.sentence-2)
[3](#range.join.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6661)
[*Example [1](#range.join.overview-example-1)*: vector<string> ss{"hello", " ", "world", "!"};for (char ch : ss | views::join) cout << ch; // prints hello world! — *end example*]
#### [25.7.14.2](#range.join.view) Class template join_view [[range.join.view]](range.join.view)
[🔗](#lib:join_view)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<V>>class join_view : public view_interface<join_view<V>> {private:using *InnerRng* = range_reference_t<V>; // *exposition only*// [[range.join.iterator]](#range.join.iterator "25.7.14.3Class template join_­view::iterator"), class template join_view::*iterator*template<bool Const>struct *iterator*; // *exposition only*// [[range.join.sentinel]](#range.join.sentinel "25.7.14.4Class template join_­view::sentinel"), class template join_view::*sentinel*template<bool Const>struct *sentinel*; // *exposition only* V *base_* = V(); // *exposition only**non-propagating-cache*<iterator_t<V>> *outer_*; // *exposition only*, present only// when ![forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>*non-propagating-cache*<remove_cv_t<*InnerRng*>> *inner_*; // *exposition only*, present only// if is_reference_v<*InnerRng*> is falsepublic: join_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> = default; constexpr explicit join_view(V base); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr auto begin() {if constexpr ([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>) {constexpr bool use_const = [*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V> && is_reference_v<*InnerRng*>; return *iterator*<use_const>{*this, ranges::begin(*base_*)}; } else {*outer_* = ranges::begin(*base_*); return *iterator*<false>{*this}; }}constexpr auto begin() constrequires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const V> && is_reference_v<range_reference_t<const V>> &&[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<const V>>{ return *iterator*<true>{*this, ranges::begin(*base_*)}; }constexpr auto end() {if constexpr ([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V> && is_reference_v<*InnerRng*> && [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*InnerRng*> &&[common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<*InnerRng*>)return *iterator*<[*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>>{*this, ranges::end(*base_*)}; elsereturn *sentinel*<[*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>>{*this}; }constexpr auto end() constrequires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const V> && is_reference_v<range_reference_t<const V>> &&[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<const V>> {if constexpr ([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<const V>> &&[common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<const V> &&[common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<const V>>)return *iterator*<true>{*this, ranges::end(*base_*)}; elsereturn *sentinel*<true>{*this}; }}; template<class R>explicit join_view(R&&) -> join_view<views::all_t<R>>;}
[🔗](#lib:join_view,constructor)
`constexpr explicit join_view(V base);
`
[1](#range.join.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6756)
*Effects*: Initializes *base_* with std::move(base)[.](#range.join.view-1.sentence-1)
#### [25.7.14.3](#range.join.iterator) Class template join_view::*iterator* [[range.join.iterator]](range.join.iterator)
[🔗](#lib:join_view::iterator)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<V>>template<bool Const>struct join_view<V>::*iterator* {private:using *Parent* = *maybe-const*<Const, join_view>; // *exposition only*using *Base* = *maybe-const*<Const, V>; // *exposition only*using *OuterIter* = iterator_t<*Base*>; // *exposition only*using *InnerIter* = iterator_t<range_reference_t<*Base*>>; // *exposition only*static 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](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") optional<*InnerIter*> *inner_*; // *exposition only**Parent** *parent_* = nullptr; // *exposition only*constexpr void *satisfy*(); // *exposition only*constexpr *OuterIter*& *outer*(); // *exposition only*constexpr const *OuterIter*& *outer*() const; // *exposition only*constexpr *iterator*(*Parent*& parent, *OuterIter* outer)requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>; // *exposition only*constexpr explicit *iterator*(*Parent*& parent)requires (![forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>); // *exposition only*public: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*<!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*>; constexpr decltype(auto) operator*() const { return ***inner_*; }constexpr *InnerIter* operator->() constrequires [*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*>; constexpr *iterator*& operator++(); constexpr void operator++(int); 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*>>; 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*>>; 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*>>; 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*>>>; 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](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4Concept indirectly_­swappable[alg.req.ind.swap]")<*InnerIter*>; };}
[1](#range.join.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6843)
*iterator*::iterator_concept is defined as follows:
- [(1.1)](#range.join.iterator-1.1)
If *ref-is-glvalue* is true, *Base* models [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]"), and range_reference_t<*Base*> models
both [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]") and [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes bidirectional_iterator_tag[.](#range.join.iterator-1.1.sentence-1)
- [(1.2)](#range.join.iterator-1.2)
Otherwise, if *ref-is-glvalue* is true and *Base* and range_reference_t<*Base*> each model [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"), then iterator_concept denotes forward_iterator_tag[.](#range.join.iterator-1.2.sentence-1)
- [(1.3)](#range.join.iterator-1.3)
Otherwise, iterator_concept denotes input_iterator_tag[.](#range.join.iterator-1.3.sentence-1)
[2](#range.join.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6858)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") iterator_category is defined
if and only if *ref-is-glvalue* is true,*Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"), andrange_reference_t<*Base*> models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")[.](#range.join.iterator-2.sentence-1)
In that case,*iterator*::iterator_category is defined as follows:
- [(2.1)](#range.join.iterator-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[.](#range.join.iterator-2.1.sentence-1)
- [(2.2)](#range.join.iterator-2.2)
If *OUTERC* and *INNERC* each model [derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<bidirectional_iterator_tag> and range_reference_t<*Base*> models [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]"), iterator_category denotes bidirectional_iterator_tag[.](#range.join.iterator-2.2.sentence-1)
- [(2.3)](#range.join.iterator-2.3)
Otherwise, if *OUTERC* and *INNERC* each model [derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<forward_iterator_tag>, iterator_category denotes forward_iterator_tag[.](#range.join.iterator-2.3.sentence-1)
- [(2.4)](#range.join.iterator-2.4)
Otherwise, iterator_category denotes input_iterator_tag[.](#range.join.iterator-2.4.sentence-1)
[3](#range.join.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6883)
*iterator*::difference_type denotes the type:common_type_t< range_difference_t<*Base*>,
range_difference_t<range_reference_t<*Base*>>>
[4](#range.join.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6891)
join_view iterators use the *satisfy* function to skip over
empty inner ranges[.](#range.join.iterator-4.sentence-1)
[🔗](#lib:outer,join_view::iterator)
`constexpr OuterIter& outer();
constexpr const OuterIter& outer() const;
`
[5](#range.join.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6902)
*Returns*: *outer_* if *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]");
otherwise, **parent_*->*outer_*[.](#range.join.iterator-5.sentence-1)
[🔗](#lib:satisfy,join_view::iterator)
`constexpr void satisfy();
`
[6](#range.join.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6914)
*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();
[🔗](#lib:join_view::iterator,constructor)
`constexpr iterator(Parent& parent, OuterIter outer)
requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[7](#range.join.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6943)
*Effects*: Initializes *outer_* with std::move(outer) and*parent_* with addressof(parent); then calls *satisfy*()[.](#range.join.iterator-7.sentence-1)
[🔗](#lib:join_view::iterator,constructor_)
`constexpr explicit iterator(Parent& parent)
requires (![forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>);
`
[8](#range.join.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6956)
*Effects*: Initializes *parent_* with addressof(parent);
then calls *satisfy*()[.](#range.join.iterator-8.sentence-1)
[🔗](#lib:join_view::iterator,constructor__)
`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](#range.join.iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6971)
*Effects*: Initializes *outer_* with std::move(i.*outer_*),*inner_* with std::move(i.*inner_*), and*parent_* with i.*parent_*[.](#range.join.iterator-9.sentence-1)
[10](#range.join.iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6977)
[*Note [1](#range.join.iterator-note-1)*:
Const can only be true when *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")[.](#range.join.iterator-10.sentence-1)
— *end note*]
[🔗](#lib:operator-%3e,join_view::iterator)
`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](#range.join.iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L6991)
*Effects*: Equivalent to: return **inner_*;
[🔗](#lib:operator++,join_view::iterator)
`constexpr iterator& operator++();
`
[12](#range.join.iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7002)
Let *inner-range* be:
- [(12.1)](#range.join.iterator-12.1)
If *ref-is-glvalue* is true, **outer*()[.](#range.join.iterator-12.1.sentence-1)
- [(12.2)](#range.join.iterator-12.2)
Otherwise, **parent_*->*inner_*[.](#range.join.iterator-12.2.sentence-1)
[13](#range.join.iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7009)
*Effects*: Equivalent to:if (++**inner_* == ranges::end(*as-lvalue*(*inner-range*))) {++*outer*(); *satisfy*();}return *this;
[🔗](#lib:operator++,join_view::iterator_)
`constexpr void operator++(int);
`
[14](#range.join.iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7027)
*Effects*: Equivalent to: ++*this[.](#range.join.iterator-14.sentence-1)
[🔗](#lib:operator++,join_view::iterator__)
`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](#range.join.iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7040)
*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,join_view::iterator)
`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](#range.join.iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7059)
*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;
[🔗](#lib:operator--,join_view::iterator_)
`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](#range.join.iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7081)
*Effects*: Equivalent to:auto tmp = *this;--*this;return tmp;
[🔗](#lib:operator==,join_view::iterator)
`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](#range.join.iterator-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7099)
*Effects*: Equivalent to:return x.*outer_* == y.*outer_* && x.*inner_* == y.*inner_*;
[🔗](#lib:iter_swap,join_view::iterator)
`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](#range.join.iterator-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7113)
*Effects*: Equivalent to: ranges::iter_swap(*x.*inner_*, *y.*inner_*);
#### [25.7.14.4](#range.join.sentinel) Class template join_view::*sentinel* [[range.join.sentinel]](range.join.sentinel)
[🔗](#lib:join_view::sentinel)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<V>>template<bool Const>struct join_view<V>::*sentinel* {private:using *Parent* = *maybe-const*<Const, join_view>; // *exposition only*using *Base* = *maybe-const*<Const, V>; // *exposition only* sentinel_t<*Base*> *end_* = sentinel_t<*Base*>(); // *exposition only*public:*sentinel*() = default; constexpr explicit *sentinel*(*Parent*& parent); constexpr *sentinel*(*sentinel*<!Const> s)requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<*Base*>>; 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); };}
[🔗](#lib:join_view::sentinel,constructor)
`constexpr explicit sentinel(Parent& parent);
`
[1](#range.join.sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7152)
*Effects*: Initializes *end_* with ranges::end(parent.*base_*)[.](#range.join.sentinel-1.sentence-1)
[🔗](#lib:join_view::sentinel,constructor_)
`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](#range.join.sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7164)
*Effects*: Initializes *end_* with std::move(s.*end_*)[.](#range.join.sentinel-2.sentence-1)
[🔗](#lib:operator==,join_view::sentinel)
`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](#range.join.sentinel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7177)
*Effects*: Equivalent to: return x.*outer*() == y.*end_*;
### [25.7.15](#range.join.with) Join with view [[range.join.with]](range.join.with)
#### [25.7.15.1](#range.join.with.overview) Overview [[range.join.with.overview]](range.join.with.overview)
[1](#range.join.with.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7186)
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[.](#range.join.with.overview-1.sentence-1)
The delimiter can be a single element or a view of elements[.](#range.join.with.overview-1.sentence-2)
[2](#range.join.with.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7193)
The name views::join_with denotes
a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.join.with.overview-2.sentence-1)
Given subexpressions E and F,
the expression views::join_with(E, F) is expression-equivalent tojoin_with_view(E, F)[.](#range.join.with.overview-2.sentence-2)
[3](#range.join.with.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7201)
[*Example [1](#range.join.with.overview-example-1)*: vector<string> 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](#range.join.with.view) Class template join_with_view [[range.join.with.view]](range.join.with.view)
[🔗](#lib:join_with_view)
namespace std::ranges {template<class R>concept [*bidirectional-common*](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]") = [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<R> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<R>; // *exposition only*template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") Pattern>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<V>>&& [view](range.view#concept:view "25.4.5Views[range.view]")<Pattern>&& [*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<range_reference_t<V>, Pattern>class join_with_view : public view_interface<join_with_view<V, Pattern>> {using *InnerRng* = range_reference_t<V>; // *exposition only* V *base_* = V(); // *exposition only**non-propagating-cache*<iterator_t<V>> *outer_it_*; // *exposition only*, present only// when ![forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>*non-propagating-cache*<remove_cv_t<*InnerRng*>> *inner_*; // *exposition only*, present only// if is_reference_v<*InnerRng*> is false Pattern *pattern_* = Pattern(); // *exposition only*// [[range.join.with.iterator]](#range.join.with.iterator "25.7.15.3Class template join_­with_­view::iterator"), class template join_with_view::*iterator*template<bool Const> struct *iterator*; // *exposition only*// [[range.join.with.sentinel]](#range.join.with.sentinel "25.7.15.4Class template join_­with_­view::sentinel"), class template join_with_view::*sentinel*template<bool Const> struct *sentinel*; // *exposition only*public: join_with_view()requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> && [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<Pattern> = default; constexpr explicit join_with_view(V base, Pattern 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); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr auto begin() {if constexpr ([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>) {constexpr bool use_const =[*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V> && is_reference_v<*InnerRng*> && [*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Pattern>; return *iterator*<use_const>{*this, ranges::begin(*base_*)}; }else {*outer_it_* = ranges::begin(*base_*); return *iterator*<false>{*this}; }}constexpr auto begin() constrequires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const V> &&[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const Pattern> && is_reference_v<range_reference_t<const V>> &&[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<const V>> &&[*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<range_reference_t<const V>, const Pattern> {return *iterator*<true>{*this, ranges::begin(*base_*)}; }constexpr auto end() {if constexpr ([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V> && is_reference_v<*InnerRng*> && [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*InnerRng*> &&[common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<*InnerRng*>)return *iterator*<[*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V> && [*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Pattern>>{*this, ranges::end(*base_*)}; elsereturn *sentinel*<[*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V> && [*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Pattern>>{*this}; }constexpr auto end() constrequires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const V> && [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const Pattern> && is_reference_v<range_reference_t<const V>> &&[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<const V>> &&[*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<range_reference_t<const V>, const Pattern> {using InnerConstRng = range_reference_t<const V>; if constexpr ([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<InnerConstRng> &&[common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<const V> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<InnerConstRng>)return *iterator*<true>{*this, ranges::end(*base_*)}; elsereturn *sentinel*<true>{*this}; }}; template<class R, class P> join_with_view(R&&, P&&) -> join_with_view<views::all_t<R>, views::all_t<P>>; template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R> join_with_view(R&&, range_value_t<range_reference_t<R>>)-> join_with_view<views::all_t<R>, single_view<range_value_t<range_reference_t<R>>>>;}
[🔗](#lib:join_with_view,constructor)
`constexpr explicit join_with_view(V base, Pattern pattern);
`
[1](#range.join.with.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7311)
*Effects*: Initializes *base_* with std::move(base) and*pattern_* with std::move(pattern)[.](#range.join.with.view-1.sentence-1)
[🔗](#lib:join_with_view,constructor_)
`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](#range.join.with.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7326)
*Effects*: Initializes *base_* with views::all(std::forward<R>(r)) and*pattern_* with views::single(std::move(e))[.](#range.join.with.view-2.sentence-1)
#### [25.7.15.3](#range.join.with.iterator) Class template join_with_view::*iterator* [[range.join.with.iterator]](range.join.with.iterator)
[🔗](#lib:join_with_view::iterator)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") Pattern>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<V>>&& [view](range.view#concept:view "25.4.5Views[range.view]")<Pattern> && [*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<range_reference_t<V>, Pattern>template<bool Const>class join_with_view<V, Pattern>::*iterator* {using *Parent* = *maybe-const*<Const, join_with_view>; // *exposition only*using *Base* = *maybe-const*<Const, V>; // *exposition only*using *InnerBase* = range_reference_t<*Base*>; // *exposition only*using *PatternBase* = *maybe-const*<Const, Pattern>; // *exposition only*using *OuterIter* = iterator_t<*Base*>; // *exposition only*using *InnerIter* = iterator_t<*InnerBase*>; // *exposition only*using *PatternIter* = iterator_t<*PatternBase*>; // *exposition only*static constexpr bool *ref-is-glvalue* = is_reference_v<*InnerBase*>; // *exposition only**Parent** *parent_* = nullptr; // *exposition only**OuterIter* *outer_it_* = *OuterIter*(); // *exposition only*, present only// if *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") variant<*PatternIter*, *InnerIter*> *inner_it_*; // *exposition only*constexpr *iterator*(*Parent*& parent, *OuterIter* outer)requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>; // *exposition only*constexpr explicit *iterator*(*Parent*& parent)requires (![forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>); // *exposition only*constexpr *OuterIter*& *outer*(); // *exposition only*constexpr const *OuterIter*& *outer*() const; // *exposition only*constexpr auto& *update-inner*(); // *exposition only*constexpr auto& *get-inner*(); // *exposition only*constexpr void *satisfy*(); // *exposition only*public: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*<!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*>; constexpr decltype(auto) operator*() const; constexpr *iterator*& operator++(); constexpr void operator++(int); 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*>; 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*>; 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*>; 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*>; 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](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4Concept indirectly_­swappable[alg.req.ind.swap]")<*InnerIter*, *PatternIter*> { visit(ranges::iter_swap, x.*inner_it_*, y.*inner_it_*); }};}
[1](#range.join.with.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7414)
*iterator*::iterator_concept is defined as follows:
- [(1.1)](#range.join.with.iterator-1.1)
If *ref-is-glvalue* is true,*Base* models [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]"), and*InnerBase* and *PatternBase* each model [*bidirectional-common*](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]"),
then iterator_concept denotes bidirectional_iterator_tag[.](#range.join.with.iterator-1.1.sentence-1)
- [(1.2)](#range.join.with.iterator-1.2)
Otherwise, if *ref-is-glvalue* is true and*Base* and *InnerBase* each model [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes forward_iterator_tag[.](#range.join.with.iterator-1.2.sentence-1)
- [(1.3)](#range.join.with.iterator-1.3)
Otherwise, iterator_concept denotes input_iterator_tag[.](#range.join.with.iterator-1.3.sentence-1)
[2](#range.join.with.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7431)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") iterator_category is defined
if and only if *ref-is-glvalue* is true, and*Base* and *InnerBase* each model [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")[.](#range.join.with.iterator-2.sentence-1)
In that case,*iterator*::iterator_category is defined as follows:
- [(2.1)](#range.join.with.iterator-2.1)
Let *OUTERC* denoteiterator_traits<*OuterIter*>::iterator_category,
let *INNERC* denoteiterator_traits<*InnerIter*>::iterator_category, and
let *PATTERNC* denoteiterator_traits<*PatternIter*>::iterator_category[.](#range.join.with.iterator-2.1.sentence-1)
- [(2.2)](#range.join.with.iterator-2.2)
Ifis_reference_v<common_reference_t<iter_reference_t<*InnerIter*>,
iter_reference_t<*PatternIter*>>> is false,iterator_category denotes input_iterator_tag[.](#range.join.with.iterator-2.2.sentence-1)
- [(2.3)](#range.join.with.iterator-2.3)
Otherwise,
if *OUTERC*, *INNERC*, and *PATTERNC* each model [derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<bidirectional_iterator_tag> and *InnerBase* and *PatternBase* each model [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]"),iterator_category denotes bidirectional_iterator_tag[.](#range.join.with.iterator-2.3.sentence-1)
- [(2.4)](#range.join.with.iterator-2.4)
Otherwise,
if *OUTERC*, *INNERC*, and *PATTERNC* each model [derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<forward_iterator_tag>,iterator_category denotes forward_iterator_tag[.](#range.join.with.iterator-2.4.sentence-1)
- [(2.5)](#range.join.with.iterator-2.5)
Otherwise, iterator_category denotes input_iterator_tag[.](#range.join.with.iterator-2.5.sentence-1)
[3](#range.join.with.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7469)
*iterator*::value_type denotes the type:common_type_t<iter_value_t<*InnerIter*>, iter_value_t<*PatternIter*>>
[4](#range.join.with.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7475)
*iterator*::difference_type denotes the type:common_type_t< iter_difference_t<*OuterIter*>,
iter_difference_t<*InnerIter*>,
iter_difference_t<*PatternIter*>>
[🔗](#lib:outer,join_with_view::iterator)
`constexpr OuterIter& outer();
constexpr const OuterIter& outer() const;
`
[5](#range.join.with.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7491)
*Returns*: *outer_it_* if *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]");
otherwise, **parent_*->*outer_it_*[.](#range.join.with.iterator-5.sentence-1)
[🔗](#lib:update-inner,join_with_view::iterator)
`constexpr auto& update-inner();
`
[6](#range.join.with.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7503)
*Effects*: Equivalent to:if constexpr (*ref-is-glvalue*)return *as-lvalue*(**outer*());elsereturn *parent_*->*inner_*.*emplace-deref*(*outer*());
[🔗](#lib:get-inner,join_with_view::iterator)
`constexpr auto& get-inner();
`
[7](#range.join.with.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7520)
*Effects*: Equivalent to:if constexpr (*ref-is-glvalue*)return *as-lvalue*(**outer*());elsereturn **parent_*->*inner_*;
[🔗](#lib:satisfy,join_with_view::iterator)
`constexpr void satisfy();
`
[8](#range.join.with.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7537)
*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](#range.join.with.iterator-note-1)*:
join_with_view iterators use the *satisfy* function
to skip over empty inner ranges[.](#range.join.with.iterator-8.sentence-2)
— *end note*]
[🔗](#lib:join_with_view::iterator,constructor)
`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](#range.join.with.iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7574)
*Effects*: Initializes *parent_* with addressof(parent)[.](#range.join.with.iterator-9.sentence-1)
For the first overload, also initializes*outer_it_* with std::move(outer)[.](#range.join.with.iterator-9.sentence-2)
Then, equivalent to:if (*outer*() != ranges::end(*parent_*->*base_*)) {*inner_it_*.template emplace<1>(ranges::begin(*update-inner*())); *satisfy*();}
[🔗](#lib:join_with_view::iterator,constructor_)
`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](#range.join.with.iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7597)
*Effects*: Initializes *outer_it_* withstd::move(i.*outer_it_*) and*parent_* with i.*parent_*[.](#range.join.with.iterator-10.sentence-1)
Then, equivalent to:if (i.*inner_it_*.index() == 0)*inner_it_*.template emplace<0>(std::get<0>(std::move(i.*inner_it_*)));else*inner_it_*.template emplace<1>(std::get<1>(std::move(i.*inner_it_*)));
[11](#range.join.with.iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7610)
[*Note [2](#range.join.with.iterator-note-2)*:
Const can only be true when *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")[.](#range.join.with.iterator-11.sentence-1)
— *end note*]
[🔗](#lib:operator--,join_with_view::iterator)
`constexpr decltype(auto) operator*() const;
`
[12](#range.join.with.iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7623)
*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_*);
[🔗](#lib:operator++,join_with_view::iterator)
`constexpr iterator& operator++();
`
[13](#range.join.with.iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7639)
*Effects*: Equivalent to:visit([](auto& it){ ++it; }, *inner_it_*);*satisfy*();return *this;
[🔗](#lib:operator++,join_with_view::iterator_)
`constexpr void operator++(int);
`
[14](#range.join.with.iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7655)
*Effects*: Equivalent to ++*this[.](#range.join.with.iterator-14.sentence-1)
[🔗](#lib:operator++,join_with_view::iterator__)
`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](#range.join.with.iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7667)
*Effects*: Equivalent to:*iterator* tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,join_with_view::iterator_)
`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](#range.join.with.iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7685)
*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;
[🔗](#lib:operator--,join_with_view::iterator__)
`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](#range.join.with.iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7726)
*Effects*: Equivalent to:*iterator* tmp = *this;--*this;return tmp;
[🔗](#lib:operator==,join_with_view::iterator)
`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](#range.join.with.iterator-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7744)
*Effects*: Equivalent to:return x.*outer_it_* == y.*outer_it_* && x.*inner_it_* == y.*inner_it_*;
#### [25.7.15.4](#range.join.with.sentinel) Class template join_with_view::*sentinel* [[range.join.with.sentinel]](range.join.with.sentinel)
[🔗](#lib:join_with_view::sentinel)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") Pattern>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<V>>&& [view](range.view#concept:view "25.4.5Views[range.view]")<Pattern> && [*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<range_reference_t<V>, Pattern>template<bool Const>class join_with_view<V, Pattern>::*sentinel* {using *Parent* = *maybe-const*<Const, join_with_view>; // *exposition only*using *Base* = *maybe-const*<Const, V>; // *exposition only* sentinel_t<*Base*> *end_* = sentinel_t<*Base*>(); // *exposition only*constexpr explicit *sentinel*(*Parent*& parent); // *exposition only*public:*sentinel*() = default; 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*>>; 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); };}
[🔗](#lib:join_with_view::sentinel,constructor)
`constexpr explicit sentinel(Parent& parent);
`
[1](#range.join.with.sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7786)
*Effects*: Initializes *end_* with ranges::end(parent.*base_*)[.](#range.join.with.sentinel-1.sentence-1)
[🔗](#lib:join_with_view::sentinel,constructor_)
`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](#range.join.with.sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7798)
*Effects*: Initializes *end_* with std::move(s.*end_*)[.](#range.join.with.sentinel-2.sentence-1)
[🔗](#lib:operator==,join_with_view::sentinel)
`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](#range.join.with.sentinel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7811)
*Effects*: Equivalent to: return x.*outer*() == y.*end_*;
### [25.7.16](#range.lazy.split) Lazy split view [[range.lazy.split]](range.lazy.split)
#### [25.7.16.1](#range.lazy.split.overview) Overview [[range.lazy.split.overview]](range.lazy.split.overview)
[1](#range.lazy.split.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7820)
lazy_split_view takes a view and a delimiter, and splits
the view into subranges on the delimiter[.](#range.lazy.split.overview-1.sentence-1)
The delimiter can be
a single element or a view of elements[.](#range.lazy.split.overview-1.sentence-2)
[2](#range.lazy.split.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7825)
The name views::lazy_split denotes a
range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.lazy.split.overview-2.sentence-1)
Given subexpressions E and F,
the expression views::lazy_split(E, F) is expression-equivalent tolazy_split_view(E, F)[.](#range.lazy.split.overview-2.sentence-2)
[3](#range.lazy.split.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7833)
[*Example [1](#range.lazy.split.overview-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 the*quick*brown*fox* — *end example*]
#### [25.7.16.2](#range.lazy.split.view) Class template lazy_split_view [[range.lazy.split.view]](range.lazy.split.view)
[🔗](#lib:lazy_split_view)
namespace std::ranges {template<auto> struct *require-constant*; // *exposition only*template<class R>concept [*tiny-range*](#concept:tiny-range "25.7.16.2Class template lazy_­split_­view[range.lazy.split.view]") = // *exposition only*[sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<R> &&requires { typename *require-constant*<remove_reference_t<R>::size()>; } &&(remove_reference_t<R>::size() <= 1); template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") Pattern>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [view](range.view#concept:view "25.4.5Views[range.view]")<Pattern> &&[indirectly_comparable](alg.req.ind.cmp#concept:indirectly_comparable "24.3.7.5Concept indirectly_­comparable[alg.req.ind.cmp]")<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V> || [*tiny-range*](#concept:tiny-range "25.7.16.2Class template lazy_­split_­view[range.lazy.split.view]")<Pattern>)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<V>> *current_*; // *exposition only*, present only// if [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V> is false// [[range.lazy.split.outer]](#range.lazy.split.outer "25.7.16.3Class template lazy_­split_­view::outer-iterator"), class template lazy_split_view::*outer-iterator*template<bool> struct *outer-iterator*; // *exposition only*// [[range.lazy.split.inner]](#range.lazy.split.inner "25.7.16.5Class template lazy_­split_­view::inner-iterator"), class template lazy_split_view::*inner-iterator*template<bool> struct *inner-iterator*; // *exposition only*public: lazy_split_view()requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> && [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<Pattern> = default; constexpr explicit lazy_split_view(V base, Pattern 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); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr auto begin() {if constexpr ([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>) {return *outer-iterator*<[*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V> && [*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Pattern>>{*this, ranges::begin(*base_*)}; } else {*current_* = ranges::begin(*base_*); return *outer-iterator*<false>{*this}; }}constexpr auto begin() const requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V> && [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const V> {return *outer-iterator*<true>{*this, ranges::begin(*base_*)}; }constexpr auto end() requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V> {return *outer-iterator*<[*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V> && [*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Pattern>>{*this, ranges::end(*base_*)}; }constexpr auto end() const {if constexpr ([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V> && [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const V> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<const V>)return *outer-iterator*<true>{*this, ranges::end(*base_*)}; elsereturn default_sentinel; }}; template<class R, class P> lazy_split_view(R&&, P&&) -> lazy_split_view<views::all_t<R>, views::all_t<P>>; template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R> lazy_split_view(R&&, range_value_t<R>)-> lazy_split_view<views::all_t<R>, single_view<range_value_t<R>>>;}
[🔗](#lib:lazy_split_view,constructor)
`constexpr explicit lazy_split_view(V base, Pattern pattern);
`
[1](#range.lazy.split.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7935)
*Effects*: Initializes *base_* with std::move(base), and*pattern_* with std::move(pattern)[.](#range.lazy.split.view-1.sentence-1)
[🔗](#lib:lazy_split_view,constructor_)
`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](#range.lazy.split.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7950)
*Effects*: Initializes *base_* with views::all(std::forward<R>(r)), and*pattern_* with views::single(std::move(e))[.](#range.lazy.split.view-2.sentence-1)
#### [25.7.16.3](#range.lazy.split.outer) Class template lazy_split_view::*outer-iterator* [[range.lazy.split.outer]](range.lazy.split.outer)
[🔗](#lib:lazy_split_view::outer-iterator)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") Pattern>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [view](range.view#concept:view "25.4.5Views[range.view]")<Pattern> &&[indirectly_comparable](alg.req.ind.cmp#concept:indirectly_comparable "24.3.7.5Concept indirectly_­comparable[alg.req.ind.cmp]")<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V> || [*tiny-range*](#concept:tiny-range "25.7.16.2Class template lazy_­split_­view[range.lazy.split.view]")<Pattern>)template<bool Const>struct lazy_split_view<V, Pattern>::*outer-iterator* {private:using *Parent* = *maybe-const*<Const, lazy_split_view>; // *exposition only*using *Base* = *maybe-const*<Const, V>; // *exposition only**Parent** *parent_* = nullptr; // *exposition only* iterator_t<*Base*> *current_* = iterator_t<*Base*>(); // *exposition only*, present only// if V models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")bool *trailing_empty_* = false; // *exposition only*public:using iterator_concept = conditional_t<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>, forward_iterator_tag, input_iterator_tag>; using iterator_category = input_iterator_tag; // present only if *Base*// models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")// [[range.lazy.split.outer.value]](#range.lazy.split.outer.value "25.7.16.4Class lazy_­split_­view::outer-iterator::value_­type"), 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](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>); 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*>; 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*>>; constexpr value_type operator*() const; constexpr *outer-iterator*& operator++(); constexpr decltype(auto) operator++(int) {if constexpr ([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>) {auto tmp = *this; ++*this; return tmp; } else++*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*>; friend constexpr bool operator==(const *outer-iterator*& x, default_sentinel_t); };}
[1](#range.lazy.split.outer-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8016)
Many of the specifications in [[range.lazy.split]](#range.lazy.split "25.7.16Lazy split view") refer to the notional member*current* of *outer-iterator*[.](#range.lazy.split.outer-1.sentence-1)
*current* is equivalent to *current_* if V models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"), and **parent_*->*current_* otherwise[.](#range.lazy.split.outer-1.sentence-2)
[🔗](#lib:lazy_split_view::outer-iterator,constructor)
`constexpr explicit outer-iterator(Parent& parent)
requires (![forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>);
`
[2](#range.lazy.split.outer-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8029)
*Effects*: Initializes *parent_* with addressof(parent)[.](#range.lazy.split.outer-2.sentence-1)
[🔗](#lib:lazy_split_view::outer-iterator,constructor_)
`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](#range.lazy.split.outer-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8041)
*Effects*: Initializes *parent_* with addressof(parent) and *current_* with std::move(current)[.](#range.lazy.split.outer-3.sentence-1)
[🔗](#lib:lazy_split_view::outer-iterator,constructor__)
`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](#range.lazy.split.outer-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8054)
*Effects*: Initializes *parent_* with i.*parent_*,*current_* with std::move(i.*current_*), and*trailing_empty_* with i.*trailing_empty_*[.](#range.lazy.split.outer-4.sentence-1)
[🔗](#lib:operator*,lazy_split_view::outer-iterator)
`constexpr value_type operator*() const;
`
[5](#range.lazy.split.outer-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8067)
*Effects*: Equivalent to: return value_type{*this};
[🔗](#lib:operator++,lazy_split_view::outer-iterator)
`constexpr outer-iterator& operator++();
`
[6](#range.lazy.split.outer-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8078)
*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*](#concept:tiny-range "25.7.16.2Class template lazy_­split_­view[range.lazy.split.view]")<Pattern>) {*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;
[🔗](#lib:operator==,lazy_split_view::outer-iterator)
`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](#range.lazy.split.outer-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8119)
*Effects*: Equivalent to:return x.*current_* == y.*current_* && x.*trailing_empty_* == y.*trailing_empty_*;
[🔗](#lib:operator==,lazy_split_view::outer-iterator_)
`friend constexpr bool operator==(const outer-iterator& x, default_sentinel_t);
`
[8](#range.lazy.split.outer-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8133)
*Effects*: Equivalent to:return x.*current* == ranges::end(x.*parent_*->*base_*) && !x.*trailing_empty_*;
#### [25.7.16.4](#range.lazy.split.outer.value) Class lazy_split_view::*outer-iterator*::value_type [[range.lazy.split.outer.value]](range.lazy.split.outer.value)
[🔗](#lib:lazy_split_view::outer-iterator::value_type)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") Pattern>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [view](range.view#concept:view "25.4.5Views[range.view]")<Pattern> &&[indirectly_comparable](alg.req.ind.cmp#concept:indirectly_comparable "24.3.7.5Concept indirectly_­comparable[alg.req.ind.cmp]")<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V> || [*tiny-range*](#concept:tiny-range "25.7.16.2Class template lazy_­split_­view[range.lazy.split.view]")<Pattern>)template<bool Const>struct lazy_split_view<V, Pattern>::*outer-iterator*<Const>::value_type : view_interface<value_type> {private:*outer-iterator* *i_* = *outer-iterator*(); // *exposition only*constexpr explicit value_type(*outer-iterator* i); // *exposition only*public:constexpr *inner-iterator*<Const> begin() const; constexpr default_sentinel_t end() const noexcept; };}
[🔗](#lib:lazy_split_view::outer-iterator::value_type,constructor)
`constexpr explicit value_type(outer-iterator i);
`
[1](#range.lazy.split.outer.value-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8171)
*Effects*: Initializes *i_* with std::move(i)[.](#range.lazy.split.outer.value-1.sentence-1)
[🔗](#lib:begin,lazy_split_view::outer-iterator::value_type)
`constexpr inner-iterator<Const> begin() const;
`
[2](#range.lazy.split.outer.value-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8182)
*Effects*: Equivalent to: return *inner-iterator*<Const>{*i_*};
[🔗](#lib:end,lazy_split_view::outer-iterator::value_type)
`constexpr default_sentinel_t end() const noexcept;
`
[3](#range.lazy.split.outer.value-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8193)
*Effects*: Equivalent to: return default_sentinel;
#### [25.7.16.5](#range.lazy.split.inner) Class template lazy_split_view::*inner-iterator* [[range.lazy.split.inner]](range.lazy.split.inner)
[🔗](#lib:lazy_split_view::inner-iterator)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") Pattern>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [view](range.view#concept:view "25.4.5Views[range.view]")<Pattern> &&[indirectly_comparable](alg.req.ind.cmp#concept:indirectly_comparable "24.3.7.5Concept indirectly_­comparable[alg.req.ind.cmp]")<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V> || [*tiny-range*](#concept:tiny-range "25.7.16.2Class template lazy_­split_­view[range.lazy.split.view]")<Pattern>)template<bool Const>struct lazy_split_view<V, Pattern>::*inner-iterator* {private:using *Base* = *maybe-const*<Const, V>; // *exposition only**outer-iterator*<Const> *i_* = *outer-iterator*<Const>(); // *exposition only*bool *incremented_* = false; // *exposition only*public:using iterator_concept = typename *outer-iterator*<Const>::iterator_concept; using iterator_category = *see below*; // present only if *Base*// models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")using value_type = range_value_t<*Base*>; using difference_type = range_difference_t<*Base*>; *inner-iterator*() = default; constexpr explicit *inner-iterator*(*outer-iterator*<Const> i); constexpr const iterator_t<*Base*>& base() const & noexcept; constexpr iterator_t<*Base*> base() && requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>; constexpr decltype(auto) operator*() const { return **i_*.*current*; }constexpr *inner-iterator*& operator++(); constexpr decltype(auto) operator++(int) {if constexpr ([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>) {auto tmp = *this; ++*this; return tmp; } else++*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*>; 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](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<*Base*>>; };}
[1](#range.lazy.split.inner-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8257)
If *Base* does not model [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") there is no member iterator_category[.](#range.lazy.split.inner-1.sentence-1)
Otherwise, the [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") iterator_category denotes:
- [(1.1)](#range.lazy.split.inner-1.1)
forward_iterator_tag ifiterator_traits<iterator_t<*Base*>>::iterator_category models[derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<forward_iterator_tag>;
- [(1.2)](#range.lazy.split.inner-1.2)
otherwise, iterator_traits<iterator_t<*Base*>>::iterator_category[.](#range.lazy.split.inner-1.sentence-2)
[🔗](#lib:lazy_split_view::inner-iterator,constructor)
`constexpr explicit inner-iterator(outer-iterator<Const> i);
`
[2](#range.lazy.split.inner-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8275)
*Effects*: Initializes *i_* with std::move(i)[.](#range.lazy.split.inner-2.sentence-1)
[🔗](#lib:base,lazy_split_view::inner-iterator)
`constexpr const iterator_t<Base>& base() const & noexcept;
`
[3](#range.lazy.split.inner-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8286)
*Effects*: Equivalent to: return *i_*.*current*;
[🔗](#lib:base,lazy_split_view::inner-iterator_)
`constexpr iterator_t<Base> base() && requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>;
`
[4](#range.lazy.split.inner-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8297)
*Effects*: Equivalent to: return std::move(*i_*.*current*);
[🔗](#lib:operator++,lazy_split_view::inner-iterator)
`constexpr inner-iterator& operator++();
`
[5](#range.lazy.split.inner-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8308)
*Effects*: Equivalent to:*incremented_* = true;if constexpr (![forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>) {if constexpr (Pattern::size() == 0) {return *this; }}++*i_*.*current*;return *this;
[🔗](#lib:operator==,lazy_split_view::inner-iterator)
`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](#range.lazy.split.inner-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8330)
*Effects*: Equivalent to: return x.*i_*.*current* == y.*i_*.*current*;
[🔗](#lib:operator==,lazy_split_view::inner-iterator_)
`friend constexpr bool operator==(const inner-iterator& x, default_sentinel_t);
`
[7](#range.lazy.split.inner-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8341)
*Effects*: Equivalent to:auto [pcur, pend] = subrange{x.*i_*.*parent_*->*pattern_*};auto end = ranges::end(x.*i_*.*parent_*->*base_*);if constexpr ([*tiny-range*](#concept:tiny-range "25.7.16.2Class template lazy_­split_­view[range.lazy.split.view]")<Pattern>) {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;}
[🔗](#lib:iter_swap,lazy_split_view::inner-iterator)
`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](#range.lazy.split.inner-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8373)
*Effects*: Equivalent toranges::iter_swap(x.*i_*.*current*, y.*i_*.*current*)[.](#range.lazy.split.inner-8.sentence-1)
### [25.7.17](#range.split) Split view [[range.split]](range.split)
#### [25.7.17.1](#range.split.overview) Overview [[range.split.overview]](range.split.overview)
[1](#range.split.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8383)
split_view takes a view and a delimiter, and
splits the view into subranges on the delimiter[.](#range.split.overview-1.sentence-1)
The delimiter can be a single element or a view of elements[.](#range.split.overview-1.sentence-2)
[2](#range.split.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8388)
The name views::split denotes
a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.split.overview-2.sentence-1)
Given subexpressions E and F,
the expression views::split(E, F) is expression-equivalent tosplit_view(E, F)[.](#range.split.overview-2.sentence-2)
[3](#range.split.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8395)
[*Example [1](#range.split.overview-example-1)*: string str{"the quick brown fox"};for (auto word : views::split(str, ' ')) { cout << string_view(word) << '*';}// The above prints the*quick*brown*fox* — *end example*]
#### [25.7.17.2](#range.split.view) Class template split_view [[range.split.view]](range.split.view)
[🔗](#lib:split_view)
namespace std::ranges {template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") V, [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") Pattern>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [view](range.view#concept:view "25.4.5Views[range.view]")<Pattern> &&[indirectly_comparable](alg.req.ind.cmp#concept:indirectly_comparable "24.3.7.5Concept indirectly_­comparable[alg.req.ind.cmp]")<iterator_t<V>, iterator_t<Pattern>, 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]](#range.split.iterator "25.7.17.3Class split_­view::iterator"), class split_view::*iterator*struct *iterator*; // *exposition only*// [[range.split.sentinel]](#range.split.sentinel "25.7.17.4Class split_­view::sentinel"), class split_view::*sentinel*struct *sentinel*; // *exposition only*public: split_view()requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> && [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<Pattern> = default; constexpr explicit split_view(V base, Pattern 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); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr *iterator* begin(); constexpr auto end() {if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V>) {return *iterator*{*this, ranges::end(*base_*), {}}; } else {return *sentinel*{*this}; }}constexpr subrange<iterator_t<V>> *find-next*(iterator_t<V>); // *exposition only*}; template<class R, class P> split_view(R&&, P&&) -> split_view<views::all_t<R>, views::all_t<P>>; template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") R> split_view(R&&, range_value_t<R>)-> split_view<views::all_t<R>, single_view<range_value_t<R>>>;}
[🔗](#lib:split_view,constructor)
`constexpr explicit split_view(V base, Pattern pattern);
`
[1](#range.split.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8466)
*Effects*: Initializes *base_* with std::move(base), and*pattern_* with std::move(pattern)[.](#range.split.view-1.sentence-1)
[🔗](#lib:split_view,constructor_)
`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](#range.split.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8481)
*Effects*: Initializes *base_* with views::all(std::forward<R>(r)), and*pattern_* with views::single(std::move(e))[.](#range.split.view-2.sentence-1)
[🔗](#lib:begin,split_view)
`constexpr iterator begin();
`
[3](#range.split.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8493)
*Returns*: {*this, ranges::begin(*base_*), *find-next*(ranges::begin(*base_*))}[.](#range.split.view-3.sentence-1)
[4](#range.split.view-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8497)
*Remarks*: In order to provide the amortized constant time complexity
required by the [range](range.range#concept:range "25.4.2Ranges[range.range]") concept,
this function caches the result within the split_view for use on subsequent calls[.](#range.split.view-4.sentence-1)
[🔗](#lib:find-next,split_view)
`constexpr subrange<iterator_t<V>> find-next(iterator_t<V> it);
`
[5](#range.split.view-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8511)
*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](#range.split.iterator) Class split_view::*iterator* [[range.split.iterator]](range.split.iterator)
[🔗](#lib:split_view::iterator)
namespace std::ranges {template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") V, [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") Pattern>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [view](range.view#concept:view "25.4.5Views[range.view]")<Pattern> &&[indirectly_comparable](alg.req.ind.cmp#concept:indirectly_comparable "24.3.7.5Concept indirectly_­comparable[alg.req.ind.cmp]")<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to>class split_view<V, Pattern>::*iterator* {private: split_view* *parent_* = nullptr; // *exposition only* iterator_t<V> *cur_* = iterator_t<V>(); // *exposition only* subrange<iterator_t<V>> *next_* = subrange<iterator_t<V>>(); // *exposition only*bool *trailing_empty_* = false; // *exposition only*public:using iterator_concept = forward_iterator_tag; using iterator_category = input_iterator_tag; using value_type = subrange<iterator_t<V>>; using difference_type = range_difference_t<V>; *iterator*() = default; constexpr *iterator*(split_view& parent, iterator_t<V> current, subrange<iterator_t<V>> next); constexpr iterator_t<V> base() const; constexpr value_type operator*() const; constexpr *iterator*& operator++(); constexpr *iterator* operator++(int); friend constexpr bool operator==(const *iterator*& x, const *iterator*& y); };}
[🔗](#lib:split_view::iterator,constructor)
`constexpr iterator(split_view& parent, iterator_t<V> current, subrange<iterator_t<V>> next);
`
[1](#range.split.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8565)
*Effects*: Initializes *parent_* with addressof(parent),*cur_* with std::move(current), and*next_* with std::move(next)[.](#range.split.iterator-1.sentence-1)
[🔗](#lib:base,split_view::iterator)
`constexpr iterator_t<V> base() const;
`
[2](#range.split.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8578)
*Effects*: Equivalent to: return *cur_*;
[🔗](#lib:operator*,split_view::iterator)
`constexpr value_type operator*() const;
`
[3](#range.split.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8589)
*Effects*: Equivalent to: return {*cur_*, *next_*.begin()};
[🔗](#lib:operator++,split_view::iterator)
`constexpr iterator& operator++();
`
[4](#range.split.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8600)
*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;
[🔗](#lib:operator++,split_view::iterator_)
`constexpr iterator operator++(int);
`
[5](#range.split.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8626)
*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;
[🔗](#lib:operator==,split_view::iterator)
`friend constexpr bool operator==(const iterator& x, const iterator& y);
`
[6](#range.split.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8642)
*Effects*: Equivalent to:return x.*cur_* == y.*cur_* && x.*trailing_empty_* == y.*trailing_empty_*;
#### [25.7.17.4](#range.split.sentinel) Class split_view::*sentinel* [[range.split.sentinel]](range.split.sentinel)
[🔗](#lib:split_view::sentinel)
namespace std::ranges {template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") V, [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") Pattern>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [view](range.view#concept:view "25.4.5Views[range.view]")<Pattern> &&[indirectly_comparable](alg.req.ind.cmp#concept:indirectly_comparable "24.3.7.5Concept indirectly_­comparable[alg.req.ind.cmp]")<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to>struct split_view<V, Pattern>::*sentinel* {private: sentinel_t<V> *end_* = sentinel_t<V>(); // *exposition only*public:*sentinel*() = default; constexpr explicit *sentinel*(split_view& parent); friend constexpr bool operator==(const *iterator*& x, const *sentinel*& y); };}
[🔗](#lib:split_view::sentinel,constructor)
`constexpr explicit sentinel(split_view& parent);
`
[1](#range.split.sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8677)
*Effects*: Initializes *end_* with ranges::end(parent.*base_*)[.](#range.split.sentinel-1.sentence-1)
[🔗](#lib:operator==,split_view::sentinel)
`friend constexpr bool operator==(const iterator& x, const sentinel& y);
`
[2](#range.split.sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8688)
*Effects*: Equivalent to: return x.*cur_* == y.*end_* && !x.*trailing_empty_*;
### [25.7.18](#range.concat) Concat view [[range.concat]](range.concat)
#### [25.7.18.1](#range.concat.overview) Overview [[range.concat.overview]](range.concat.overview)
[1](#range.concat.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8697)
concat_view presents a view that concatenates all the underlying ranges[.](#range.concat.overview-1.sentence-1)
[2](#range.concat.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8700)
The name views::concat denotes
a customization point object ([[customization.point.object]](customization.point.object "16.3.3.3.5Customization Point Object types"))[.](#range.concat.overview-2.sentence-1)
Given a pack of subexpressions Es...,
the expression views::concat(Es...) is expression-equivalent to
- [(2.1)](#range.concat.overview-2.1)
views::all(Es...) if Es is a pack with only one element
whose type models [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]"),
- [(2.2)](#range.concat.overview-2.2)
otherwise, concat_view(Es...)[.](#range.concat.overview-2.sentence-2)
[*Example [1](#range.concat.overview-example-1)*: vector<int> 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](#range.concat.view) Class template concat_view [[range.concat.view]](range.concat.view)
[🔗](#lib:concat_view)
namespace std::ranges {template<class... Rs>using *concat-reference-t* = common_reference_t<range_reference_t<Rs>...>; // *exposition only*template<class... Rs>using *concat-value-t* = common_type_t<range_value_t<Rs>...>; // *exposition only*template<class... Rs>using *concat-rvalue-reference-t* = // *exposition only* common_reference_t<range_rvalue_reference_t<Rs>...>; 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*template<class... Rs>concept [*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]") = *see below*; // *exposition only*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*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*template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")... Views>requires ([view](range.view#concept:view "25.4.5Views[range.view]")<Views> && ...) && (sizeof...(Views) > 0) &&[*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<Views...>class concat_view : public view_interface<concat_view<Views...>> { tuple<Views...> *views_*; // *exposition only*// [[range.concat.iterator]](#range.concat.iterator "25.7.18.3Class concat_­view::iterator"), class template concat_view::*iterator*template<bool> class *iterator*; // *exposition only*public:constexpr concat_view() = default; constexpr explicit concat_view(Views... 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() constrequires ([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...>; constexpr auto end() requires (!([*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Views> && ...)); constexpr auto end() constrequires ([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...>; 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> && ...); }; template<class... R> concat_view(R&&...) -> concat_view<views::all_t<R>...>;}
[🔗](#concept:concat-indirectly-readable)
`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](#range.concat.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8780)
The exposition-only [*concat-indirectly-readable*](#concept:concat-indirectly-readable "25.7.18.2Class template concat_­view[range.concat.view]") concept
is equivalent to:template<class Ref, class RRef, class It>concept [*concat-indirectly-readable-impl*](#concept:concat-indirectly-readable-impl "25.7.18.2Class template concat_­view[range.concat.view]") = // *exposition only*requires (const It it) {{ *it } -> [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<Ref>; { ranges::iter_move(it) } -> [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<RRef>; };
template<class... Rs>concept [*concat-indirectly-readable*](#concept:concat-indirectly-readable "25.7.18.2Class template concat_­view[range.concat.view]") = // *exposition only*[common_reference_with](concept.commonref#concept:common_reference_with "18.4.5Concept common_­reference_­with[concept.commonref]")<*concat-reference-t*<Rs...>&&, *concat-value-t*<Rs...>&> &&[common_reference_with](concept.commonref#concept:common_reference_with "18.4.5Concept common_­reference_­with[concept.commonref]")<*concat-reference-t*<Rs...>&&, *concat-rvalue-reference-t*<Rs...>&&> &&[common_reference_with](concept.commonref#concept:common_reference_with "18.4.5Concept common_­reference_­with[concept.commonref]")<*concat-rvalue-reference-t*<Rs...>&&, *concat-value-t*<Rs...> const&> &&([*concat-indirectly-readable-impl*](#concept:concat-indirectly-readable-impl "25.7.18.2Class template concat_­view[range.concat.view]")<*concat-reference-t*<Rs...>, *concat-rvalue-reference-t*<Rs...>,
iterator_t<Rs>> && ...);
[🔗](#concept:concatable)
`template<class... Rs>
concept [concatable](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]") = see below; // exposition only
`
[2](#range.concat.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8811)
The exposition-only [*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]") concept is equivalent to:template<class... Rs>concept [*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]") = requires { // *exposition only*typename *concat-reference-t*<Rs...>; typename *concat-value-t*<Rs...>; typename *concat-rvalue-reference-t*<Rs...>; } && [*concat-indirectly-readable*](#concept:concat-indirectly-readable "25.7.18.2Class template concat_­view[range.concat.view]")<Rs...>;
[🔗](#concept:concat-is-random-access)
`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](#range.concat.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8829)
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*](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]") = // *exposition only*[*all-random-access*](#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Rs...> &&([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<*maybe-const*<Const, Fs>> && ...);
[🔗](#concept:concat-is-bidirectional)
`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](#range.concat.view-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8848)
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*](#concept:concat-is-bidirectional "25.7.18.2Class template concat_­view[range.concat.view]") = // *exposition only*[*all-bidirectional*](#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Rs...> &&([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<*maybe-const*<Const, Fs>> && ...);
[🔗](#lib:concat_view,constructor)
`constexpr explicit concat_view(Views... views);
`
[5](#range.concat.view-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8867)
*Effects*: Initializes *views_* with std::move(views)...[.](#range.concat.view-5.sentence-1)
[🔗](#lib:begin,concat_view)
`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](#range.concat.view-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8880)
*Effects*: Let *is-const* betrue for the const-qualified overload, andfalse otherwise[.](#range.concat.view-6.sentence-1)
Equivalent to:*iterator*<*is-const*> it(this, in_place_index<0>, ranges::begin(std::get<0>(*views_*)));
it.template *satisfy*<0>();return it;
[🔗](#lib:end,concat_view)
`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](#range.concat.view-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8901)
*Effects*: Let *is-const* betrue for the const-qualified overload, andfalse otherwise[.](#range.concat.view-7.sentence-1)
Equivalent to:constexpr auto N = sizeof...(Views);if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<*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;}
[🔗](#lib:size,concat_view)
`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](#range.concat.view-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8925)
*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](#range.concat.iterator) Class concat_view::*iterator* [[range.concat.iterator]](range.concat.iterator)
[🔗](#lib:iterator,concat_view)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")... Views>requires ([view](range.view#concept:view "25.4.5Views[range.view]")<Views> && ...) && (sizeof...(Views) > 0) &&[*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<Views...>template<bool Const>class 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 only*template<size_t N>constexpr void *satisfy*(); // *exposition only*template<size_t N>constexpr void *prev*(); // *exposition only*template<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](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<*base-iter*, Args&&...>; public:*iterator*() = default; 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>> && ...); constexpr decltype(auto) operator*() const; constexpr *iterator*& operator++(); constexpr void operator++(int); constexpr *iterator* operator++(int)requires [*all-forward*](#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; constexpr *iterator*& operator--()requires [*concat-is-bidirectional*](#concept:concat-is-bidirectional "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>; constexpr *iterator* operator--(int)requires [*concat-is-bidirectional*](#concept:concat-is-bidirectional "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>; 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...>; 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...>; constexpr decltype(auto) operator[](difference_type n) constrequires [*concat-is-random-access*](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>; 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>>> && ...); friend constexpr bool operator==(const *iterator*& it, default_sentinel_t); 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>>> && ...)); 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...>; 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...>; 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...>; 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...>; 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](#range.concat.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9035)
*iterator*::iterator_concept is defined as follows:
- [(1.1)](#range.concat.iterator-1.1)
If[*concat-is-random-access*](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...> is modeled,
then iterator_concept denotes random_access_iterator_tag[.](#range.concat.iterator-1.1.sentence-1)
- [(1.2)](#range.concat.iterator-1.2)
Otherwise, if[*concat-is-bidirectional*](#concept:concat-is-bidirectional "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...> is modeled,
then iterator_concept denotes bidirectional_iterator_tag[.](#range.concat.iterator-1.2.sentence-1)
- [(1.3)](#range.concat.iterator-1.3)
Otherwise, if[*all-forward*](#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> is modeled,
then iterator_concept denotes forward_iterator_tag[.](#range.concat.iterator-1.3.sentence-1)
- [(1.4)](#range.concat.iterator-1.4)
Otherwise, iterator_concept denotes input_iterator_tag[.](#range.concat.iterator-1.4.sentence-1)
[2](#range.concat.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9054)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") iterator_category is defined
if and only if[*all-forward*](#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> is modeled[.](#range.concat.iterator-2.sentence-1)
In that case,*iterator*::iterator_category is defined as follows:
- [(2.1)](#range.concat.iterator-2.1)
Ifis_reference_v<*concat-reference-t*<*maybe-const*<Const, Views>...>> is false,
then iterator_category denotes input_iterator_tag[.](#range.concat.iterator-2.1.sentence-1)
- [(2.2)](#range.concat.iterator-2.2)
Otherwise,
let Cs denote the pack of typesiterator_traits<iterator_t<*maybe-const*<Const, Views>>>::iterator_category...[.](#range.concat.iterator-2.2.sentence-1)
* [(2.2.1)](#range.concat.iterator-2.2.1)
If([derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<Cs, random_access_iterator_tag> && ...) && *concat-is-random-access*<Const, Views...> is true,iterator_category denotes random_access_iterator_tag[.](#range.concat.iterator-2.2.1.sentence-1)
* [(2.2.2)](#range.concat.iterator-2.2.2)
Otherwise, if([derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<Cs, bidirectional_iterator_tag> && ...) && *concat-is-bidirectional*<Const, Views...> is true,iterator_category denotes bidirectional_iterator_tag[.](#range.concat.iterator-2.2.2.sentence-1)
* [(2.2.3)](#range.concat.iterator-2.2.3)
Otherwise, if([derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<Cs, forward_iterator_tag> && ...) is true,iterator_category denotes forward_iterator_tag[.](#range.concat.iterator-2.2.3.sentence-1)
* [(2.2.4)](#range.concat.iterator-2.2.4)
Otherwise, iterator_category denotes input_iterator_tag[.](#range.concat.iterator-2.2.4.sentence-1)
[🔗](#lib:satisfy,concat_view::iterator)
`template<size_t N>
constexpr void satisfy();
`
[3](#range.concat.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9100)
*Effects*: Equivalent to:if constexpr (N < (sizeof...(Views) - 1)) {if (std::get<N>(*it_*) == ranges::end(std::get<N>(*parent_*->*views_*))) {*it_*.template emplace<N + 1>(ranges::begin(std::get<N + 1>(*parent_*->*views_*))); *satisfy*<N + 1>(); }}
[🔗](#lib:prev,concat_view::iterator)
`template<size_t N>
constexpr void prev();
`
[4](#range.concat.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9120)
*Effects*: Equivalent to:if constexpr (N == 0) {--std::get<0>(*it_*);} else {if (std::get<N>(*it_*) == ranges::begin(std::get<N>(*parent_*->*views_*))) {*it_*.template emplace<N - 1>(ranges::end(std::get<N - 1>(*parent_*->*views_*))); *prev*<N - 1>(); } else {--std::get<N>(*it_*); }}
[🔗](#lib:advance-fwd,concat_view::iterator)
`template<size_t N>
constexpr void advance-fwd(difference_type offset, difference_type steps);
`
[5](#range.concat.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9144)
*Effects*: Equivalent to:using underlying_diff_type = iter_difference_t<variant_alternative_t<N, *base-iter*>>;if constexpr (N == sizeof...(Views) - 1) { std::get<N>(*it_*) += static_cast<underlying_diff_type>(steps);} else {auto n_size = ranges::distance(std::get<N>(*parent_*->*views_*)); if (offset + steps < n_size) { std::get<N>(*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); }}
[🔗](#lib:advance-bwd,concat_view::iterator)
`template<size_t N>
constexpr void advance-bwd(difference_type offset, difference_type steps);
`
[6](#range.concat.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9170)
*Effects*: Equivalent to:using underlying_diff_type = iter_difference_t<variant_alternative_t<N, *base-iter*>>;if constexpr (N == 0) { std::get<N>(*it_*) -= static_cast<underlying_diff_type>(steps);} else {if (offset >= steps) { std::get<N>(*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); }}
[🔗](#lib:concat_view::iterator,constructor)
`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](#range.concat.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9198)
*Effects*: Initializes *parent_* with parent, and
initializes *it_* with std::forward<Args>(args)...[.](#range.concat.iterator-7.sentence-1)
[🔗](#lib:concat_view::iterator,constructor_)
`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](#range.concat.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9212)
*Preconditions*: it.*it_*.valueless_by_exception() is false[.](#range.concat.iterator-8.sentence-1)
[9](#range.concat.iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9216)
*Effects*: Initializes *parent_* with it.*parent_*, and
let i be it.*it_*.index(),
initializes *it_* with*base-iter*(in_place_index<i>, std::get<i>(std::move(it.*it_*)))[.](#range.concat.iterator-9.sentence-1)
[🔗](#lib:operator*,concat_view::iterator)
`constexpr decltype(auto) operator*() const;
`
[10](#range.concat.iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9230)
*Preconditions*: *it_*.valueless_by_exception() is false[.](#range.concat.iterator-10.sentence-1)
[11](#range.concat.iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9234)
*Effects*: Equivalent to:using reference = *concat-reference-t*<*maybe-const*<Const, Views>...>;return std::visit([](auto&& it) -> reference { return *it; }, *it_*);
[🔗](#lib:operator++,concat_view::iterator)
`constexpr iterator& operator++();
`
[12](#range.concat.iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9250)
*Preconditions*: *it_*.valueless_by_exception() is false[.](#range.concat.iterator-12.sentence-1)
[13](#range.concat.iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9254)
*Effects*: Let i be *it_*.index()[.](#range.concat.iterator-13.sentence-1)
Equivalent to:++std::get<i>(*it_*);*satisfy*<i>();return *this;
[🔗](#lib:operator++,concat_view::iterator_)
`constexpr void operator++(int);
`
[14](#range.concat.iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9271)
*Effects*: Equivalent to:++*this;
[🔗](#lib:operator++,concat_view::iterator__)
`constexpr iterator operator++(int)
requires [all-forward](#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
`
[15](#range.concat.iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9286)
*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,concat_view::iterator)
`constexpr iterator& operator--()
requires [concat-is-bidirectional](#concept:concat-is-bidirectional "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>;
`
[16](#range.concat.iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9303)
*Preconditions*: *it_*.valueless_by_exception() is false[.](#range.concat.iterator-16.sentence-1)
[17](#range.concat.iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9307)
*Effects*: Let i be *it_*.index()[.](#range.concat.iterator-17.sentence-1)
Equivalent to:*prev*<i>();return *this;
[🔗](#lib:operator--,concat_view::iterator_)
`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](#range.concat.iterator-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9324)
*Effects*: Equivalent to:auto tmp = *this;--*this;return tmp;
[🔗](#lib:operator+=,concat_view::iterator)
`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](#range.concat.iterator-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9341)
*Preconditions*: *it_*.valueless_by_exception() is false[.](#range.concat.iterator-19.sentence-1)
[20](#range.concat.iterator-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9345)
*Effects*: Let i be *it_*.index()[.](#range.concat.iterator-20.sentence-1)
Equivalent to:if (n > 0) {*advance-fwd*<i>(std::get<i>(*it_*) - ranges::begin(std::get<i>(*parent_*->*views_*)), n);} else if (n < 0) {*advance-bwd*<i>(std::get<i>(*it_*) - ranges::begin(std::get<i>(*parent_*->*views_*)), -n);}return *this;
[🔗](#lib:operator-=,concat_view::iterator)
`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](#range.concat.iterator-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9366)
*Effects*: Equivalent to:*this += -n;return *this;
[🔗](#lib:operator%5b%5d,concat_view::iterator)
`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](#range.concat.iterator-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9382)
*Effects*: Equivalent to:return *((*this) + n);
[🔗](#lib:operator==,concat_view::iterator)
`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](#range.concat.iterator-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9397)
*Preconditions*: x.*it_*.valueless_by_exception() andy.*it_*.valueless_by_exception() are each false[.](#range.concat.iterator-23.sentence-1)
[24](#range.concat.iterator-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9402)
*Effects*: Equivalent to:return x.*it_* == y.*it_*;
[🔗](#lib:operator==,concat_view::iterator_)
`friend constexpr bool operator==(const iterator& it, default_sentinel_t);
`
[25](#range.concat.iterator-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9416)
*Preconditions*: it.*it_*.valueless_by_exception() is false[.](#range.concat.iterator-25.sentence-1)
[26](#range.concat.iterator-26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9420)
*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_*));
[🔗](#lib:operator%3c,concat_view::iterator)
`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](#range.concat.iterator-27)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9446)
*Preconditions*: x.*it_*.valueless_by_exception() andy.*it_*.valueless_by_exception() are each false[.](#range.concat.iterator-27.sentence-1)
[28](#range.concat.iterator-28)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9451)
Let op be the operator[.](#range.concat.iterator-28.sentence-1)
[29](#range.concat.iterator-29)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9454)
*Effects*: Equivalent to:return x.*it_* op y.*it_*;
[🔗](#lib:operator+,concat_view::iterator)
`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](#range.concat.iterator-30)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9469)
*Effects*: Equivalent to:auto temp = it;
temp += n;return temp;
[🔗](#lib:operator+,concat_view::iterator_)
`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](#range.concat.iterator-31)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9486)
*Effects*: Equivalent to:return it + n;
[🔗](#lib:operator-,concat_view::iterator)
`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](#range.concat.iterator-32)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9501)
*Effects*: Equivalent to:auto temp = it;
temp -= n;return temp;
[🔗](#lib:operator-,concat_view::iterator_)
`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](#range.concat.iterator-33)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9518)
*Preconditions*: x.*it_*.valueless_by_exception() andy.*it_*.valueless_by_exception() are each false[.](#range.concat.iterator-33.sentence-1)
[34](#range.concat.iterator-34)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9523)
*Effects*: Letix denote x.*it_*.index() andiy denote y.*it_*.index()[.](#range.concat.iterator-34.sentence-1)
- [(34.1)](#range.concat.iterator-34.1)
If ix > iy, letdy beranges::distance(std::get<iy>(y.*it_*), ranges::end(std::get<iy>(y.*parent_*->*views_*))),dx beranges::distance(ranges::begin(std::get<ix>(x.*parent_*->*views_*)), std::get<ix>(x.*it_*)). Let s denote the sum of the sizes of all the rangesstd::get<i>(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;
- [(34.2)](#range.concat.iterator-34.2)
otherwise, if ix < iy is true,
equivalent to:return -(y - x);
- [(34.3)](#range.concat.iterator-34.3)
otherwise, equivalent to:return std::get<ix>(x.*it_*) - std::get<iy>(y.*it_*);
[🔗](#lib:operator-,concat_view::iterator__)
`friend constexpr difference_type operator-(const iterator& x, default_sentinel_t)
requires see below;
`
[35](#range.concat.iterator-35)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9571)
*Preconditions*: x.*it_*.valueless_by_exception() is false[.](#range.concat.iterator-35.sentence-1)
[36](#range.concat.iterator-36)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9575)
*Effects*: Letix denote x.*it_*.index(),dx beranges::distance(std::get<ix>(x.*it_*), ranges::end(std::get<ix>(x.*parent_*->*views_*)))[.](#range.concat.iterator-36.sentence-1)
Let s denote the sum of the sizes of all the rangesstd::get<i>(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](#range.concat.iterator-37)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9594)
*Remarks*: Let Fs be the pack that consists of all elements of Views except the first element,
the expression in the [*requires-clause*](temp.pre#nt:requires-clause "13.1Preamble[temp.pre]") is equivalent to:([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*<Const, Views>>> && ...) &&([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<*maybe-const*<Const, Fs>> && ...)
[🔗](#lib:operator-,concat_view::iterator___)
`friend constexpr difference_type operator-(default_sentinel_t, const iterator& x)
requires see below;
`
[38](#range.concat.iterator-38)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9614)
*Effects*: Equivalent to:return -(x - default_sentinel);
[39](#range.concat.iterator-39)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9621)
*Remarks*: Let Fs be the pack that consists of all elements of Views except the first element,
the expression in the [*requires-clause*](temp.pre#nt:requires-clause "13.1Preamble[temp.pre]") is equivalent to:([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*<Const, Views>>> && ...) &&([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<*maybe-const*<Const, Fs>> && ...)
[🔗](#lib:iter_move,concat_view::iterator)
`friend constexpr decltype(auto) iter_move(const iterator& it) noexcept(see below);
`
[40](#range.concat.iterator-40)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9639)
*Preconditions*: it.*it_*.valueless_by_exception() is false[.](#range.concat.iterator-40.sentence-1)
[41](#range.concat.iterator-41)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9643)
*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](#range.concat.iterator-42)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9654)
*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>...>>) &&...)
[🔗](#lib:iter_swap,concat_view::iterator)
`friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(see below)
requires see below;
`
[43](#range.concat.iterator-43)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9673)
*Preconditions*: x.*it_*.valueless_by_exception() andy.*it_*.valueless_by_exception() are each false[.](#range.concat.iterator-43.sentence-1)
[44](#range.concat.iterator-44)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9678)
*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](#range.concat.iterator-45)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9692)
*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[.](#range.concat.iterator-45.sentence-1)
The expression in the [*requires-clause*](temp.pre#nt:requires-clause "13.1Preamble[temp.pre]") is equivalent to[swappable_with](concept.swappable#concept:swappable_with "18.4.9Concept swappable[concept.swappable]")<iter_reference_t<*iterator*>, iter_reference_t<*iterator*>> &&(... && [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>>>)
### [25.7.19](#range.counted) Counted view [[range.counted]](range.counted)
[1](#range.counted-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9712)
A counted view presents a view of the elements
of the counted range ([[iterator.requirements.general]](iterator.requirements.general "24.3.1General")) i+[0, n) for an iterator i and non-negative integer n[.](#range.counted-1.sentence-1)
[2](#range.counted-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9718)
The name views::counted denotes
a customization point object ([[customization.point.object]](customization.point.object "16.3.3.3.5Customization Point Object types"))[.](#range.counted-2.sentence-1)
Let E and F be expressions,
let T be decay_t<decltype((E))>, and
let D be iter_difference_t<T>[.](#range.counted-2.sentence-2)
If decltype((F)) does not model[convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<D>,views::counted(E, F) is ill-formed[.](#range.counted-2.sentence-3)
[*Note [1](#range.counted-note-1)*:
This case can result in substitution failure
when views::counted(E, F) appears in the immediate context of a template instantiation[.](#range.counted-2.sentence-4)
— *end note*]
Otherwise, views::counted(E, F) is expression-equivalent to:
- [(2.1)](#range.counted-2.1)
If T models [contiguous_iterator](iterator.concept.contiguous#concept:contiguous_iterator "24.3.4.14Concept contiguous_­iterator[iterator.concept.contiguous]"),
then span(to_address(E), static_cast<size_t>(static_cast<D>(F)))[.](#range.counted-2.1.sentence-1)
- [(2.2)](#range.counted-2.2)
Otherwise, if T models [random_access_iterator](iterator.concept.random.access#concept:random_access_iterator "24.3.4.13Concept random_­access_­iterator[iterator.concept.random.access]"),
then subrange(E, E + static_cast<D>(F)),
except that E is evaluated only once[.](#range.counted-2.2.sentence-1)
- [(2.3)](#range.counted-2.3)
Otherwise,subrange(counted_iterator(E, F), default_sentinel)[.](#range.counted-2.3.sentence-1)
### [25.7.20](#range.common) Common view [[range.common]](range.common)
#### [25.7.20.1](#range.common.overview) Overview [[range.common.overview]](range.common.overview)
[1](#range.common.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9754)
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[.](#range.common.overview-1.sentence-1)
[2](#range.common.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9759)
[*Note [1](#range.common.overview-note-1)*:
common_view is useful for calling legacy algorithms that expect
a range's iterator and sentinel types to be the same[.](#range.common.overview-2.sentence-1)
— *end note*]
[3](#range.common.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9765)
The name views::common denotes a
range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.common.overview-3.sentence-1)
Given a subexpression E,
the expression views::common(E) is expression-equivalent to:
- [(3.1)](#range.common.overview-3.1)
views::all(E),
if decltype((E)) models [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]") and views::all(E) is a well-formed expression[.](#range.common.overview-3.1.sentence-1)
- [(3.2)](#range.common.overview-3.2)
Otherwise, common_view{E}[.](#range.common.overview-3.2.sentence-1)
[4](#range.common.overview-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9779)
[*Example [1](#range.common.overview-example-1)*: // Legacy algorithm:template<class ForwardIterator> size_t count(ForwardIterator first, ForwardIterator last);
template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") R>void my_algo(R&& r) {auto&& common = views::common(r); auto cnt = count(common.begin(), common.end()); // ...} — *end example*]
#### [25.7.20.2](#range.common.view) Class template common_view [[range.common.view]](range.common.view)
[🔗](#lib:common_view)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V>requires (![common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V> && [copyable](concepts.object#concept:copyable "18.6Object concepts[concepts.object]")<iterator_t<V>>)class common_view : public view_interface<common_view<V>> {private: V *base_* = V(); // *exposition only*public: common_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> = default; constexpr explicit common_view(V r); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr auto begin() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>) {if constexpr ([random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<V> && [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>)return ranges::begin(*base_*); elsereturn common_iterator<iterator_t<V>, sentinel_t<V>>(ranges::begin(*base_*)); }constexpr auto begin() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V> {if constexpr ([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>)return ranges::begin(*base_*); elsereturn common_iterator<iterator_t<const V>, sentinel_t<const V>>(ranges::begin(*base_*)); }constexpr auto end() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>) {if constexpr ([random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<V> && [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>)return ranges::begin(*base_*) + ranges::distance(*base_*); elsereturn common_iterator<iterator_t<V>, sentinel_t<V>>(ranges::end(*base_*)); }constexpr auto end() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V> {if constexpr ([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>)return ranges::begin(*base_*) + ranges::distance(*base_*); elsereturn common_iterator<iterator_t<const V>, sentinel_t<const V>>(ranges::end(*base_*)); }constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V> {return ranges::size(*base_*); }constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V> {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> {return ranges::reserve_hint(*base_*); }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> {return ranges::reserve_hint(*base_*); }}; template<class R> common_view(R&&) -> common_view<views::all_t<R>>;}
[🔗](#lib:common_view,constructor)
`constexpr explicit common_view(V base);
`
[1](#range.common.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9872)
*Effects*: Initializes *base_* with std::move(base)[.](#range.common.view-1.sentence-1)
### [25.7.21](#range.reverse) Reverse view [[range.reverse]](range.reverse)
#### [25.7.21.1](#range.reverse.overview) Overview [[range.reverse.overview]](range.reverse.overview)
[1](#range.reverse.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9881)
reverse_view takes a bidirectional view and produces
another view that iterates the same elements in reverse order[.](#range.reverse.overview-1.sentence-1)
[2](#range.reverse.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9885)
The name views::reverse denotes a
range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.reverse.overview-2.sentence-1)
Given a subexpression E, the expressionviews::reverse(E) is expression-equivalent to:
- [(2.1)](#range.reverse.overview-2.1)
If the type of E is
a (possibly cv-qualified) specialization of reverse_view,
then E.base()[.](#range.reverse.overview-2.1.sentence-1)
- [(2.2)](#range.reverse.overview-2.2)
Otherwise, if the type of E is cv subrange<reverse_iterator<I>, reverse_iterator<I>, K> for some iterator type I and
value K of type subrange_kind,
* [(2.2.1)](#range.reverse.overview-2.2.1)
if K is subrange_kind::sized, thensubrange<I, I, K>(E.end().base(), E.begin().base(), E.size());
* [(2.2.2)](#range.reverse.overview-2.2.2)
otherwise, subrange<I, I, K>(E.end().base(), E.begin().base())[.](#range.reverse.overview-2.2.sentence-1)
However, in either case E is evaluated only once[.](#range.reverse.overview-2.2.sentence-2)
- [(2.3)](#range.reverse.overview-2.3)
Otherwise, reverse_view{E}[.](#range.reverse.overview-2.3.sentence-1)
[3](#range.reverse.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9912)
[*Example [1](#range.reverse.overview-example-1)*: vector<int> 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](#range.reverse.view) Class template reverse_view [[range.reverse.view]](range.reverse.view)
[🔗](#lib:reverse_view)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V>requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<V>class reverse_view : public view_interface<reverse_view<V>> {private: V *base_* = V(); // *exposition only*public: reverse_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> = default; constexpr explicit reverse_view(V r); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr reverse_iterator<iterator_t<V>> begin(); 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>; 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>; constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V> {return ranges::size(*base_*); }constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V> {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> {return ranges::reserve_hint(*base_*); }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> {return ranges::reserve_hint(*base_*); }}; template<class R> reverse_view(R&&) -> reverse_view<views::all_t<R>>;}
[🔗](#lib:reverse_view,constructor)
`constexpr explicit reverse_view(V base);
`
[1](#range.reverse.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9976)
*Effects*: Initializes *base_* with std::move(base)[.](#range.reverse.view-1.sentence-1)
[🔗](#lib:begin,reverse_view)
`constexpr reverse_iterator<iterator_t<V>> begin();
`
[2](#range.reverse.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9987)
*Returns*: make_reverse_iterator(ranges::next(ranges::begin(*base_*), ranges::end(*base_*)))
[3](#range.reverse.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9993)
*Remarks*: In order to provide the amortized constant time complexity required by
the [range](range.range#concept:range "25.4.2Ranges[range.range]") concept, this function caches the result within thereverse_view for use on subsequent calls[.](#range.reverse.view-3.sentence-1)
[🔗](#lib:begin,reverse_view_)
`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](#range.reverse.view-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10007)
*Effects*: Equivalent to: return make_reverse_iterator(ranges::end(*base_*));
[🔗](#lib:end,reverse_view)
`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](#range.reverse.view-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10019)
*Effects*: Equivalent to: return make_reverse_iterator(ranges::begin(*base_*));
### [25.7.22](#range.as.const) As const view [[range.as.const]](range.as.const)
#### [25.7.22.1](#range.as.const.overview) Overview [[range.as.const.overview]](range.as.const.overview)
[1](#range.as.const.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10028)
as_const_view presents a view of an underlying sequence as constant[.](#range.as.const.overview-1.sentence-1)
That is, the elements of an as_const_view cannot be modified[.](#range.as.const.overview-1.sentence-2)
[2](#range.as.const.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10032)
The name views::as_const denotes
a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.as.const.overview-2.sentence-1)
Let E be an expression,
let T be decltype((E)), and
let U be remove_cvref_t<T>[.](#range.as.const.overview-2.sentence-2)
The expression views::as_const(E) is expression-equivalent to:
- [(2.1)](#range.as.const.overview-2.1)
If views::all_t<T> models [constant_range](range.refinements#concept:constant_range "25.4.6Other range refinements[range.refinements]"),
then views::all(E)[.](#range.as.const.overview-2.1.sentence-1)
- [(2.2)](#range.as.const.overview-2.2)
Otherwise,
if U denotes empty_view<X> for some type X, then auto(views::empty<const X>)[.](#range.as.const.overview-2.2.sentence-1)
- [(2.3)](#range.as.const.overview-2.3)
Otherwise,
if U denotes span<X, Extent> for some type X and some extent Extent,
then span<const X, Extent>(E)[.](#range.as.const.overview-2.3.sentence-1)
- [(2.4)](#range.as.const.overview-2.4)
Otherwise,
if U denotes ref_view<X> for some type X andconst X models [constant_range](range.refinements#concept:constant_range "25.4.6Other range refinements[range.refinements]"),
then ref_view(static_cast<const X&>(E.base()))[.](#range.as.const.overview-2.4.sentence-1)
- [(2.5)](#range.as.const.overview-2.5)
Otherwise,
if E is an lvalue,const U models [constant_range](range.refinements#concept:constant_range "25.4.6Other range refinements[range.refinements]"), andU does not model [view](range.view#concept:view "25.4.5Views[range.view]"),
then ref_view(static_cast<const U&>(E))[.](#range.as.const.overview-2.5.sentence-1)
- [(2.6)](#range.as.const.overview-2.6)
Otherwise, as_const_view(E)[.](#range.as.const.overview-2.6.sentence-1)
[3](#range.as.const.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10067)
[*Example [1](#range.as.const.overview-example-1)*: template<[constant_range](range.refinements#concept:constant_range "25.4.6Other range refinements[range.refinements]") R>void cant_touch_this(R&&);
vector<char> hammer = {'m', 'c'};
span<char> beat = hammer;
cant_touch_this(views::as_const(beat)); // will not modify the elements of hammer — *end example*]
#### [25.7.22.2](#range.as.const.view) Class template as_const_view [[range.as.const.view]](range.as.const.view)
[🔗](#lib:as_const_view::iterator)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V>requires [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<V>class as_const_view : public view_interface<as_const_view<V>> { V *base_* = V(); // *exposition only*public: as_const_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> = default; constexpr explicit as_const_view(V base); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr auto begin() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>) { return ranges::cbegin(*base_*); }constexpr auto begin() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V> { return ranges::cbegin(*base_*); }constexpr auto end() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>) { return ranges::cend(*base_*); }constexpr auto end() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V> { return ranges::cend(*base_*); }constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V> { return ranges::size(*base_*); }constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V> { 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>{ return ranges::reserve_hint(*base_*); }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>{ return ranges::reserve_hint(*base_*); }}; template<class R> as_const_view(R&&) -> as_const_view<views::all_t<R>>;}
[🔗](#lib:as_const_view::iterator,constructor)
`constexpr explicit as_const_view(V base);
`
[1](#range.as.const.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10122)
*Effects*: Initializes *base_* with std::move(base)[.](#range.as.const.view-1.sentence-1)
### [25.7.23](#range.elements) Elements view [[range.elements]](range.elements)
#### [25.7.23.1](#range.elements.overview) Overview [[range.elements.overview]](range.elements.overview)
[1](#range.elements.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10131)
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[.](#range.elements.overview-1.sentence-1)
[2](#range.elements.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10137)
The name views::elements<N> denotes
a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.elements.overview-2.sentence-1)
Given a subexpression E and constant expression N,
the expression views::elements<N>(E) is expression-equivalent toelements_view<views::all_t<decltype((E))>, N>{E}[.](#range.elements.overview-2.sentence-2)
[*Example [1](#range.elements.overview-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](#range.elements.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10166)
keys_view is an alias for elements_view<R, 0>, and
is useful for extracting keys from associative containers[.](#range.elements.overview-3.sentence-1)
[*Example [2](#range.elements.overview-example-2)*: auto names = historical_figures | views::keys;for (auto&& name : names) { cout << name << ' '; // prints Babbage Hamilton Lovelace Turing } — *end example*]
[4](#range.elements.overview-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10179)
values_view is an alias for elements_view<R, 1>, and
is useful for extracting values from associative containers[.](#range.elements.overview-4.sentence-1)
[*Example [3](#range.elements.overview-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](#range.elements.view) Class template elements_view [[range.elements.view]](range.elements.view)
[🔗](#lib:elements_view)
namespace std::ranges {template<class T, size_t N>concept [*has-tuple-element*](#concept:has-tuple-element "25.7.23.2Class template elements_­view[range.elements.view]") = // *exposition only*[*tuple-like*](tuple.like#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]")<T> && N < tuple_size_v<T>; template<class T, size_t N>concept [*returnable-element*](#concept:returnable-element "25.7.23.2Class template elements_­view[range.elements.view]") = // *exposition only* is_reference_v<T> || [move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13Concept move_­constructible[concept.moveconstructible]")<tuple_element_t<N, T>>; template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, size_t N>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [*has-tuple-element*](#concept:has-tuple-element "25.7.23.2Class template elements_­view[range.elements.view]")<range_value_t<V>, N> &&[*has-tuple-element*](#concept:has-tuple-element "25.7.23.2Class template elements_­view[range.elements.view]")<remove_reference_t<range_reference_t<V>>, N> &&[*returnable-element*](#concept:returnable-element "25.7.23.2Class template elements_­view[range.elements.view]")<range_reference_t<V>, N>class elements_view : public view_interface<elements_view<V, N>> {public: elements_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> = default; constexpr explicit elements_view(V base); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr auto begin() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>){ return *iterator*<false>(ranges::begin(*base_*)); }constexpr auto begin() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V>{ return *iterator*<true>(ranges::begin(*base_*)); }constexpr auto end() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V> && ![common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V>){ return *sentinel*<false>{ranges::end(*base_*)}; }constexpr auto end() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V>){ return *iterator*<false>{ranges::end(*base_*)}; }constexpr auto end() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V>{ return *sentinel*<true>{ranges::end(*base_*)}; }constexpr auto end() const requires [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<const V>{ return *iterator*<true>{ranges::end(*base_*)}; }constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>{ return ranges::size(*base_*); }constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V>{ 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>{ return ranges::reserve_hint(*base_*); }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>{ return ranges::reserve_hint(*base_*); }private:// [[range.elements.iterator]](#range.elements.iterator "25.7.23.3Class template elements_­view::iterator"), class template elements_view::*iterator*template<bool> class *iterator*; // *exposition only*// [[range.elements.sentinel]](#range.elements.sentinel "25.7.23.4Class template elements_­view::sentinel"), class template elements_view::*sentinel*template<bool> class *sentinel*; // *exposition only* V *base_* = V(); // *exposition only*};}
[🔗](#lib:elements_view,constructor)
`constexpr explicit elements_view(V base);
`
[1](#range.elements.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10267)
*Effects*: Initializes *base_* with std::move(base)[.](#range.elements.view-1.sentence-1)
#### [25.7.23.3](#range.elements.iterator) Class template elements_view::*iterator* [[range.elements.iterator]](range.elements.iterator)
[🔗](#lib:elements_view::iterator)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, size_t N>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [*has-tuple-element*](#concept:has-tuple-element "25.7.23.2Class template elements_­view[range.elements.view]")<range_value_t<V>, N> &&[*has-tuple-element*](#concept:has-tuple-element "25.7.23.2Class template elements_­view[range.elements.view]")<remove_reference_t<range_reference_t<V>>, N> &&[*returnable-element*](#concept:returnable-element "25.7.23.2Class template elements_­view[range.elements.view]")<range_reference_t<V>, N>template<bool Const>class elements_view<V, N>::*iterator* {using *Base* = *maybe-const*<Const, V>; // *exposition only* iterator_t<*Base*> *current_* = iterator_t<*Base*>(); // *exposition only*static constexpr decltype(auto) *get-element*(const iterator_t<*Base*>& i); // *exposition only*public: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](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<iterator_t<*Base*>> = default; constexpr explicit *iterator*(iterator_t<*Base*> 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*>>; 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](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator* operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator+=(difference_type x)requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator-=(difference_type x)requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr decltype(auto) operator[](difference_type n) constrequires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>{ return *get-element*(*current_* + 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<*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 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]")<iterator_t<*Base*>>; 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*>; 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*>; 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*>; 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*>>; };}
[1](#range.elements.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10348)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") iterator_concept is defined as follows:
- [(1.1)](#range.elements.iterator-1.1)
If *Base* models [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes random_access_iterator_tag[.](#range.elements.iterator-1.1.sentence-1)
- [(1.2)](#range.elements.iterator-1.2)
Otherwise, if *Base* models [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes bidirectional_iterator_tag[.](#range.elements.iterator-1.2.sentence-1)
- [(1.3)](#range.elements.iterator-1.3)
Otherwise, if *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes forward_iterator_tag[.](#range.elements.iterator-1.3.sentence-1)
- [(1.4)](#range.elements.iterator-1.4)
Otherwise, iterator_concept denotes input_iterator_tag[.](#range.elements.iterator-1.4.sentence-1)
[2](#range.elements.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10365)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") iterator_category is defined
if and only if *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")[.](#range.elements.iterator-2.sentence-1)
In that case, iterator_category is defined as follows:
Let C denote the typeiterator_traits<iterator_t<*Base*>>::iterator_category[.](#range.elements.iterator-2.sentence-2)
- [(2.1)](#range.elements.iterator-2.1)
If std::get<N>(**current_*) is an rvalue,iterator_category denotes input_iterator_tag[.](#range.elements.iterator-2.1.sentence-1)
- [(2.2)](#range.elements.iterator-2.2)
Otherwise, if C models [derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<random_access_iterator_tag>,iterator_category denotes random_access_iterator_tag[.](#range.elements.iterator-2.2.sentence-1)
- [(2.3)](#range.elements.iterator-2.3)
Otherwise, iterator_category denotes C[.](#range.elements.iterator-2.3.sentence-1)
[🔗](#lib:get-element,elements_view::iterator)
`static constexpr decltype(auto) get-element(const iterator_t<Base>& i);
`
[3](#range.elements.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10388)
*Effects*: Equivalent to:if constexpr (is_reference_v<range_reference_t<*Base*>>) {return std::get<N>(*i);} else {using E = remove_cv_t<tuple_element_t<N, range_reference_t<*Base*>>>; return static_cast<E>(std::get<N>(*i));}
[🔗](#lib:elements_view::iterator,constructor)
`constexpr explicit iterator(iterator_t<Base> current);
`
[4](#range.elements.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10407)
*Effects*: Initializes *current_* with std::move(current)[.](#range.elements.iterator-4.sentence-1)
[🔗](#lib:elements_view::iterator,constructor_)
`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](#range.elements.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10419)
*Effects*: Initializes *current_* with std::move(i.*current_*)[.](#range.elements.iterator-5.sentence-1)
[🔗](#lib:base,elements_view::iterator)
`constexpr const iterator_t<Base>& base() const & noexcept;
`
[6](#range.elements.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10430)
*Effects*: Equivalent to: return *current_*;
[🔗](#lib:base,elements_view::iterator_)
`constexpr iterator_t<Base> base() &&;
`
[7](#range.elements.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10441)
*Effects*: Equivalent to: return std::move(*current_*);
[🔗](#lib:operator++,elements_view::iterator)
`constexpr iterator& operator++();
`
[8](#range.elements.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10452)
*Effects*: Equivalent to:++*current_*;return *this;
[🔗](#lib:operator++,elements_view::iterator_)
`constexpr void operator++(int);
`
[9](#range.elements.iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10467)
*Effects*: Equivalent to: ++*current_*[.](#range.elements.iterator-9.sentence-1)
[🔗](#lib:operator++,elements_view::iterator__)
`constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[10](#range.elements.iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10478)
*Effects*: Equivalent to:auto temp = *this;++*current_*;return temp;
[🔗](#lib:operator--,elements_view::iterator)
`constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[11](#range.elements.iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10494)
*Effects*: Equivalent to:--*current_*;return *this;
[🔗](#lib:operator--,elements_view::iterator_)
`constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[12](#range.elements.iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10509)
*Effects*: Equivalent to:auto temp = *this;--*current_*;return temp;
[🔗](#lib:operator+=,elements_view::iterator)
`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](#range.elements.iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10526)
*Effects*: Equivalent to:*current_* += n;return *this;
[🔗](#lib:operator-=,elements_view::iterator)
`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](#range.elements.iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10542)
*Effects*: Equivalent to:*current_* -= n;return *this;
[🔗](#lib:operator==,elements_view::iterator)
`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](#range.elements.iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10558)
*Effects*: Equivalent to: return x.*current_* == y.*current_*;
[🔗](#lib:operator%3c,elements_view::iterator)
`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](#range.elements.iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10570)
*Effects*: Equivalent to: return x.*current_* < y.*current_*;
[🔗](#lib:operator%3e,elements_view::iterator)
`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](#range.elements.iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10582)
*Effects*: Equivalent to: return y < x;
[🔗](#lib:operator%3c=,elements_view::iterator)
`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](#range.elements.iterator-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10594)
*Effects*: Equivalent to: return !(y < x);
[🔗](#lib:operator%3e=,elements_view::iterator)
`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](#range.elements.iterator-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10606)
*Effects*: Equivalent to: return !(x < y);
[🔗](#lib:operator%3c=%3e,elements_view::iterator)
`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](#range.elements.iterator-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10618)
*Effects*: Equivalent to: return x.*current_* <=> y.*current_*;
[🔗](#lib:operator+,elements_view::iterator)
`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](#range.elements.iterator-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10630)
*Effects*: Equivalent to: return *iterator*{x} += y;
[🔗](#lib:operator+,elements_view::iterator_)
`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](#range.elements.iterator-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10642)
*Effects*: Equivalent to: return y + x;
[🔗](#lib:operator-,elements_view::iterator)
`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](#range.elements.iterator-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10654)
*Effects*: Equivalent to: return *iterator*{x} -= y;
[🔗](#lib:operator-,elements_view::iterator_)
`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](#range.elements.iterator-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10666)
*Effects*: Equivalent to: return x.*current_* - y.*current_*;
#### [25.7.23.4](#range.elements.sentinel) Class template elements_view::*sentinel* [[range.elements.sentinel]](range.elements.sentinel)
[🔗](#lib:elements_view::sentinel)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, size_t N>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [*has-tuple-element*](#concept:has-tuple-element "25.7.23.2Class template elements_­view[range.elements.view]")<range_value_t<V>, N> &&[*has-tuple-element*](#concept:has-tuple-element "25.7.23.2Class template elements_­view[range.elements.view]")<remove_reference_t<range_reference_t<V>>, N> &&[*returnable-element*](#concept:returnable-element "25.7.23.2Class template elements_­view[range.elements.view]")<range_reference_t<V>, N>template<bool Const>class elements_view<V, N>::*sentinel* {private:using *Base* = *maybe-const*<Const, V>; // *exposition only* sentinel_t<*Base*> *end_* = sentinel_t<*Base*>(); // *exposition only*public:*sentinel*() = default; constexpr explicit *sentinel*(sentinel_t<*Base*> end); constexpr *sentinel*(*sentinel*<!Const> other)requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<*Base*>>; constexpr sentinel_t<*Base*> base() const; 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); 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); 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); };}
[🔗](#lib:elements_view::sentinel,constructor)
`constexpr explicit sentinel(sentinel_t<Base> end);
`
[1](#range.elements.sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10717)
*Effects*: Initializes *end_* with end[.](#range.elements.sentinel-1.sentence-1)
[🔗](#lib:elements_view::sentinel,constructor_)
`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](#range.elements.sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10729)
*Effects*: Initializes *end_* with std::move(other.*end_*)[.](#range.elements.sentinel-2.sentence-1)
[🔗](#lib:base,elements_view::sentinel)
`constexpr sentinel_t<Base> base() const;
`
[3](#range.elements.sentinel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10740)
*Effects*: Equivalent to: return *end_*;
[🔗](#lib:operator==,elements_view::sentinel)
`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](#range.elements.sentinel-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10753)
*Effects*: Equivalent to: return x.*current_* == y.*end_*;
[🔗](#lib:operator-,elements_view::sentinel)
`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](#range.elements.sentinel-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10767)
*Effects*: Equivalent to: return x.*current_* - y.*end_*;
[🔗](#lib:operator-,elements_view::sentinel_)
`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](#range.elements.sentinel-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10781)
*Effects*: Equivalent to: return x.*end_* - y.*current_*;
### [25.7.24](#range.enumerate) Enumerate view [[range.enumerate]](range.enumerate)
#### [25.7.24.1](#range.enumerate.overview) Overview [[range.enumerate.overview]](range.enumerate.overview)
[1](#range.enumerate.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10790)
enumerate_view is a view whose
elements represent both the position and value from
a sequence of elements[.](#range.enumerate.overview-1.sentence-1)
[2](#range.enumerate.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10796)
The name views::enumerate denotes a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.enumerate.overview-2.sentence-1)
Given a subexpression E,
the expression views::enumerate(E) is expression-equivalent toenumerate_view<views::all_t<decltype((E))>>(E)[.](#range.enumerate.overview-2.sentence-2)
[*Example [1](#range.enumerate.overview-example-1)*: vector<int> 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](#range.enumerate.view) Class template enumerate_view [[range.enumerate.view]](range.enumerate.view)
[🔗](#lib:enumerate_view_)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V>requires [*range-with-movable-references*](range.utility.helpers#concept:range-with-movable-references "25.5.2Helper concepts[range.utility.helpers]")<V>class enumerate_view : public view_interface<enumerate_view<V>> { V *base_* = V(); // *exposition only*// [[range.enumerate.iterator]](#range.enumerate.iterator "25.7.24.3Class template enumerate_­view::iterator"), class template enumerate_view::*iterator*template<bool Const>class *iterator*; // *exposition only*// [[range.enumerate.sentinel]](#range.enumerate.sentinel "25.7.24.4Class template enumerate_­view::sentinel"), class template enumerate_view::*sentinel*template<bool Const>class *sentinel*; // *exposition only*public:constexpr enumerate_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> = default; constexpr explicit enumerate_view(V base); constexpr auto begin() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>){ return *iterator*<false>(ranges::begin(*base_*), 0); }constexpr auto begin() const requires [*range-with-movable-references*](range.utility.helpers#concept:range-with-movable-references "25.5.2Helper concepts[range.utility.helpers]")<const V>{ return *iterator*<true>(ranges::begin(*base_*), 0); }constexpr auto end() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>) {if constexpr ([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V> && [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>)return *iterator*<false>(ranges::end(*base_*), ranges::distance(*base_*)); elsereturn *sentinel*<false>(ranges::end(*base_*)); }constexpr auto end() const requires [*range-with-movable-references*](range.utility.helpers#concept:range-with-movable-references "25.5.2Helper concepts[range.utility.helpers]")<const V> {if constexpr ([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const V> && [common_range](range.refinements#concept:common_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>)return *iterator*<true>(ranges::end(*base_*), ranges::distance(*base_*)); elsereturn *sentinel*<true>(ranges::end(*base_*)); }constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>{ return ranges::size(*base_*); }constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const V>{ 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>{ return ranges::reserve_hint(*base_*); }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>{ return ranges::reserve_hint(*base_*); }constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }}; template<class R> enumerate_view(R&&) -> enumerate_view<views::all_t<R>>;}
[🔗](#lib:enumerate_view,constructor)
`constexpr explicit enumerate_view(V base);
`
[1](#range.enumerate.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10878)
*Effects*: Initializes *base_* with std::move(base)[.](#range.enumerate.view-1.sentence-1)
#### [25.7.24.3](#range.enumerate.iterator) Class template enumerate_view::*iterator* [[range.enumerate.iterator]](range.enumerate.iterator)
[🔗](#lib:enumerate_view::iterator)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V>requires [*range-with-movable-references*](range.utility.helpers#concept:range-with-movable-references "25.5.2Helper concepts[range.utility.helpers]")<V>template<bool Const>class enumerate_view<V>::*iterator* {using *Base* = *maybe-const*<Const, V>; // *exposition only*public: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 only*constexpr explicit*iterator*(iterator_t<*Base*> current, difference_type pos); // *exposition only*public:*iterator*() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<iterator_t<*Base*>> = default; 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*>>; 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](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator* operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator+=(difference_type x)requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator-=(difference_type x)requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr auto operator[](difference_type n) constrequires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*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](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; 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*>; 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*>; 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](#range.enumerate.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10960)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]")*iterator*::iterator_concept is defined as follows:
- [(1.1)](#range.enumerate.iterator-1.1)
If *Base* models [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes random_access_iterator_tag[.](#range.enumerate.iterator-1.1.sentence-1)
- [(1.2)](#range.enumerate.iterator-1.2)
Otherwise, if *Base* models [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes bidirectional_iterator_tag[.](#range.enumerate.iterator-1.2.sentence-1)
- [(1.3)](#range.enumerate.iterator-1.3)
Otherwise, if *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes forward_iterator_tag[.](#range.enumerate.iterator-1.3.sentence-1)
- [(1.4)](#range.enumerate.iterator-1.4)
Otherwise, iterator_concept denotes input_iterator_tag[.](#range.enumerate.iterator-1.4.sentence-1)
[🔗](#lib:enumerate_view::iterator,constructor)
`constexpr explicit iterator(iterator_t<Base> current, difference_type pos);
`
[2](#range.enumerate.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10984)
*Effects*: Initializes *current_* with std::move(current) and*pos_* with pos[.](#range.enumerate.iterator-2.sentence-1)
[🔗](#lib:enumerate_view::iterator,constructor_)
`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](#range.enumerate.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L10997)
*Effects*: Initializes *current_* with std::move(i.*current_*) and*pos_* with i.*pos_*[.](#range.enumerate.iterator-3.sentence-1)
[🔗](#lib:base,enumerate_view::iterator)
`constexpr const iterator_t<Base>& base() const & noexcept;
`
[4](#range.enumerate.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11009)
*Effects*: Equivalent to: return *current_*;
[🔗](#lib:base,enumerate_view::iterator_)
`constexpr iterator_t<Base> base() &&;
`
[5](#range.enumerate.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11020)
*Effects*: Equivalent to: return std::move(*current_*);
[🔗](#lib:index,enumerate_view::iterator)
`constexpr difference_type index() const noexcept;
`
[6](#range.enumerate.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11031)
*Effects*: Equivalent to: return *pos_*;
[🔗](#lib:operator++,enumerate_view::iterator)
`constexpr iterator& operator++();
`
[7](#range.enumerate.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11042)
*Effects*: Equivalent to:++*current_*;++*pos_*;return *this;
[🔗](#lib:operator++,enumerate_view::iterator_)
`constexpr void operator++(int);
`
[8](#range.enumerate.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11058)
*Effects*: Equivalent to ++*this[.](#range.enumerate.iterator-8.sentence-1)
[🔗](#lib:operator++,enumerate_view::iterator__)
`constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[9](#range.enumerate.iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11069)
*Effects*: Equivalent to:auto temp = *this;++*this;return temp;
[🔗](#lib:operator--,enumerate_view::iterator)
`constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[10](#range.enumerate.iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11085)
*Effects*: Equivalent to:--*current_*;--*pos_*;return *this;
[🔗](#lib:operator--,enumerate_view::iterator_)
`constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[11](#range.enumerate.iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11101)
*Effects*: Equivalent to:auto temp = *this;--*this;return temp;
[🔗](#lib:operator+=,enumerate_view::iterator)
`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](#range.enumerate.iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11118)
*Effects*: Equivalent to:*current_* += n;*pos_* += n;return *this;
[🔗](#lib:operator-=,enumerate_view::iterator)
`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](#range.enumerate.iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11135)
*Effects*: Equivalent to:*current_* -= n;*pos_* -= n;return *this;
[🔗](#lib:operator==,enumerate_view::iterator)
`friend constexpr bool operator==(const iterator& x, const iterator& y) noexcept;
`
[14](#range.enumerate.iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11151)
*Effects*: Equivalent to: return x.*pos_* == y.*pos_*;
[🔗](#lib:operator%3c=%3e,enumerate_view::iterator)
`friend constexpr strong_ordering operator<=>(const iterator& x, const iterator& y) noexcept;
`
[15](#range.enumerate.iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11162)
*Effects*: Equivalent to: return x.*pos_* <=> y.*pos_*;
[🔗](#lib:operator+,enumerate_view::iterator)
`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](#range.enumerate.iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11174)
*Effects*: Equivalent to:auto temp = x;
temp += y;return temp;
[🔗](#lib:operator+,enumerate_view::iterator_)
`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](#range.enumerate.iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11191)
*Effects*: Equivalent to: return y + x;
[🔗](#lib:operator-,enumerate_view::iterator)
`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](#range.enumerate.iterator-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11203)
*Effects*: Equivalent to:auto temp = x;
temp -= y;return temp;
[🔗](#lib:operator-,enumerate_view::iterator_)
`friend constexpr difference_type operator-(const iterator& x, const iterator& y) noexcept;
`
[19](#range.enumerate.iterator-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11219)
*Effects*: Equivalent to: return x.*pos_* - y.*pos_*;
#### [25.7.24.4](#range.enumerate.sentinel) Class template enumerate_view::*sentinel* [[range.enumerate.sentinel]](range.enumerate.sentinel)
[🔗](#lib:enumerate_view::sentinel)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V>requires [*range-with-movable-references*](range.utility.helpers#concept:range-with-movable-references "25.5.2Helper concepts[range.utility.helpers]")<V>template<bool Const>class enumerate_view<V>::*sentinel* {using *Base* = *maybe-const*<Const, V>; // *exposition only* sentinel_t<*Base*> *end_* = sentinel_t<*Base*>(); // *exposition only*constexpr explicit *sentinel*(sentinel_t<*Base*> end); // *exposition only*public:*sentinel*() = default; 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*>>; constexpr sentinel_t<*Base*> base() const; 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); 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); 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); };}
[🔗](#lib:enumerate_view::sentinel,constructor)
`constexpr explicit sentinel(sentinel_t<Base> end);
`
[1](#range.enumerate.sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11267)
*Effects*: Initializes *end_* with std::move(end)[.](#range.enumerate.sentinel-1.sentence-1)
[🔗](#lib:enumerate_view::sentinel,constructor_)
`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](#range.enumerate.sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11279)
*Effects*: Initializes *end_* with std::move(other.*end_*)[.](#range.enumerate.sentinel-2.sentence-1)
[🔗](#lib:base,enumerate_view::sentinel)
`constexpr sentinel_t<Base> base() const;
`
[3](#range.enumerate.sentinel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11290)
*Effects*: Equivalent to: return *end_*;
[🔗](#lib:operator==,enumerate_view::sentinel)
`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](#range.enumerate.sentinel-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11303)
*Effects*: Equivalent to: return x.*current_* == y.*end_*;
[🔗](#lib:operator-,enumerate_view::sentinel)
`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](#range.enumerate.sentinel-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11317)
*Effects*: Equivalent to: return x.*current_* - y.*end_*;
[🔗](#lib:operator-,enumerate_view::sentinel_)
`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](#range.enumerate.sentinel-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11331)
*Effects*: Equivalent to: return x.*end_* - y.*current_*;
### [25.7.25](#range.zip) Zip view [[range.zip]](range.zip)
#### [25.7.25.1](#range.zip.overview) Overview [[range.zip.overview]](range.zip.overview)
[1](#range.zip.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11340)
zip_view takes any number of views and
produces a view of tuples of references
to the corresponding elements of the constituent views[.](#range.zip.overview-1.sentence-1)
[2](#range.zip.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11346)
The name views::zip denotes
a customization point object ([[customization.point.object]](customization.point.object "16.3.3.3.5Customization Point Object types"))[.](#range.zip.overview-2.sentence-1)
Given a pack of subexpressions Es...,
the expression views::zip(Es...) is expression-equivalent to
- [(2.1)](#range.zip.overview-2.1)
auto(views::empty<tuple<>>) if Es is an empty pack,
- [(2.2)](#range.zip.overview-2.2)
otherwise, zip_view<views::all_t<decltype((Es))>...>(Es...)[.](#range.zip.overview-2.sentence-2)
[*Example [1](#range.zip.overview-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](#range.zip.view) Class template zip_view [[range.zip.view]](range.zip.view)
[🔗](#lib:zip_view_)
namespace std::ranges {template<class... Rs>concept [*zip-is-common*](#concept:zip-is-common "25.7.25.2Class template zip_­view[range.zip.view]") = // *exposition only*(sizeof...(Rs) == 1 && ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<Rs> && ...)) ||(!([bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Rs> && ...) && ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<Rs> && ...)) ||(([random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<Rs> && ...) && ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<Rs> && ...)); template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")... Views>requires ([view](range.view#concept:view "25.4.5Views[range.view]")<Views> && ...) && (sizeof...(Views) > 0)class zip_view : public view_interface<zip_view<Views...>> { tuple<Views...> *views_*; // *exposition only*// [[range.zip.iterator]](#range.zip.iterator "25.7.25.3Class template zip_­view::iterator"), class template zip_view::*iterator*template<bool> class *iterator*; // *exposition only*// [[range.zip.sentinel]](#range.zip.sentinel "25.7.25.4Class template zip_­view::sentinel"), class template zip_view::*sentinel*template<bool> class *sentinel*; // *exposition only*public: zip_view() = default; constexpr explicit zip_view(Views... views); constexpr auto begin() requires (!([*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Views> && ...)) {return *iterator*<false>(*tuple-transform*(ranges::begin, *views_*)); }constexpr auto begin() const requires ([range](range.range#concept:range "25.4.2Ranges[range.range]")<const Views> && ...) {return *iterator*<true>(*tuple-transform*(ranges::begin, *views_*)); }constexpr auto end() requires (!([*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Views> && ...)) {if constexpr (![*zip-is-common*](#concept:zip-is-common "25.7.25.2Class template zip_­view[range.zip.view]")<Views...>) {return *sentinel*<false>(*tuple-transform*(ranges::end, *views_*)); } else if constexpr (([random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<Views> && ...)) {return begin() + iter_difference_t<*iterator*<false>>(size()); } else {return *iterator*<false>(*tuple-transform*(ranges::end, *views_*)); }}constexpr auto end() const requires ([range](range.range#concept:range "25.4.2Ranges[range.range]")<const Views> && ...) {if constexpr (![*zip-is-common*](#concept:zip-is-common "25.7.25.2Class template zip_­view[range.zip.view]")<const Views...>) {return *sentinel*<true>(*tuple-transform*(ranges::end, *views_*)); } else if constexpr (([random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<const Views> && ...)) {return begin() + iter_difference_t<*iterator*<true>>(size()); } else {return *iterator*<true>(*tuple-transform*(ranges::end, *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> && ...); }; template<class... Rs> zip_view(Rs&&...) -> zip_view<views::all_t<Rs>...>;}
[1](#range.zip.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11439)
Two zip_view objects have the same underlying sequence if and only if
the corresponding elements of *views_* are equal ([[concepts.equality]](concepts.equality "18.2Equality preservation"))
and have the same underlying sequence[.](#range.zip.view-1.sentence-1)
[*Note [1](#range.zip.view-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]](iterator.concept.forward "24.3.4.11Concept forward_­iterator"))[.](#range.zip.view-1.sentence-2)
— *end note*]
[🔗](#lib:zip_view,constructor)
`constexpr explicit zip_view(Views... views);
`
[2](#range.zip.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11455)
*Effects*: Initializes *views_* with std::move(views)...[.](#range.zip.view-2.sentence-1)
[🔗](#lib:size,zip_view)
`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](#range.zip.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11467)
*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](#range.zip.iterator) Class template zip_view::*iterator* [[range.zip.iterator]](range.zip.iterator)
[🔗](#lib:zip_view::iterator)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")... Views>requires ([view](range.view#concept:view "25.4.5Views[range.view]")<Views> && ...) && (sizeof...(Views) > 0)template<bool Const>class zip_view<Views...>::*iterator* { tuple<iterator_t<*maybe-const*<Const, Views>>...> *current_*; // *exposition only*constexpr explicit *iterator*(tuple<iterator_t<*maybe-const*<Const, Views>>...>); // *exposition only*public: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*<!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>> && ...); constexpr auto operator*() const; constexpr *iterator*& operator++(); constexpr void operator++(int); constexpr *iterator* operator++(int) requires [*all-forward*](#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; constexpr *iterator*& operator--() requires [*all-bidirectional*](#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; constexpr *iterator* operator--(int) requires [*all-bidirectional*](#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; constexpr *iterator*& operator+=(difference_type x)requires [*all-random-access*](#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; constexpr *iterator*& operator-=(difference_type x)requires [*all-random-access*](#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; constexpr auto operator[](difference_type n) constrequires [*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 ([equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<iterator_t<*maybe-const*<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...>; 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...>; 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 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>>> && ...); 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](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<*maybe-const*<Const, Views>>> && ...); };}
[1](#range.zip.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11540)
*iterator*::iterator_concept is defined as follows:
- [(1.1)](#range.zip.iterator-1.1)
If [*all-random-access*](#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> is modeled,
then iterator_concept denotes random_access_iterator_tag[.](#range.zip.iterator-1.1.sentence-1)
- [(1.2)](#range.zip.iterator-1.2)
Otherwise,
if [*all-bidirectional*](#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> is modeled,
then iterator_concept denotes bidirectional_iterator_tag[.](#range.zip.iterator-1.2.sentence-1)
- [(1.3)](#range.zip.iterator-1.3)
Otherwise,
if [*all-forward*](#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> is modeled,
then iterator_concept denotes forward_iterator_tag[.](#range.zip.iterator-1.3.sentence-1)
- [(1.4)](#range.zip.iterator-1.4)
Otherwise, iterator_concept denotes input_iterator_tag[.](#range.zip.iterator-1.4.sentence-1)
[2](#range.zip.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11558)
*iterator*::iterator_category is present
if and only if [*all-forward*](#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> is modeled[.](#range.zip.iterator-2.sentence-1)
[3](#range.zip.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11562)
If the invocation of any non-const member function of *iterator* exits via an exception,
the iterator acquires a singular value[.](#range.zip.iterator-3.sentence-1)
[🔗](#lib:zip_view::iterator,constructor)
`constexpr explicit iterator(tuple<iterator_t<maybe-const<Const, Views>>...> current);
`
[4](#range.zip.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11573)
*Effects*: Initializes *current_* with std::move(current)[.](#range.zip.iterator-4.sentence-1)
[🔗](#lib:zip_view::iterator,constructor_)
`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](#range.zip.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11585)
*Effects*: Initializes *current_* with std::move(i.*current_*)[.](#range.zip.iterator-5.sentence-1)
[🔗](#lib:operator*,izip_view::iterator)
`constexpr auto operator*() const;
`
[6](#range.zip.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11596)
*Effects*: Equivalent to:return *tuple-transform*([](auto& i) -> decltype(auto) { return *i; }, *current_*);
[🔗](#lib:operator++,izip_view::iterator)
`constexpr iterator& operator++();
`
[7](#range.zip.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11610)
*Effects*: Equivalent to:*tuple-for-each*([](auto& i) { ++i; }, *current_*);return *this;
[🔗](#lib:operator++,izip_view::iterator_)
`constexpr void operator++(int);
`
[8](#range.zip.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11625)
*Effects*: Equivalent to ++*this[.](#range.zip.iterator-8.sentence-1)
[🔗](#lib:operator++,izip_view::iterator__)
`constexpr iterator operator++(int) requires [all-forward](#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
`
[9](#range.zip.iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11636)
*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,izip_view::iterator)
`constexpr iterator& operator--() requires [all-bidirectional](#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
`
[10](#range.zip.iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11652)
*Effects*: Equivalent to:*tuple-for-each*([](auto& i) { --i; }, *current_*);return *this;
[🔗](#lib:operator--,izip_view::iterator_)
`constexpr iterator operator--(int) requires [all-bidirectional](#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
`
[11](#range.zip.iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11667)
*Effects*: Equivalent to:auto tmp = *this;--*this;return tmp;
[🔗](#lib:operator+=,izip_view::iterator)
`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](#range.zip.iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11684)
*Effects*: Equivalent to:*tuple-for-each*([&]<class I>(I& i) { i += iter_difference_t<I>(x); }, *current_*);return *this;
[🔗](#lib:operator-=,izip_view::iterator)
`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](#range.zip.iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11700)
*Effects*: Equivalent to:*tuple-for-each*([&]<class I>(I& i) { i -= iter_difference_t<I>(x); }, *current_*);return *this;
[🔗](#lib:operator%5b%5d,izip_view::iterator)
`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](#range.zip.iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11716)
*Effects*: Equivalent to:return *tuple-transform*([&]<class I>(I& i) -> decltype(auto) {return i[iter_difference_t<I>(n)];}, *current_*);
[🔗](#lib:operator==,izip_view::iterator)
`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](#range.zip.iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11733)
*Returns*:
- [(15.1)](#range.zip.iterator-15.1)
x.*current_* == y.*current_* if [*all-bidirectional*](#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> is true[.](#range.zip.iterator-15.1.sentence-1)
- [(15.2)](#range.zip.iterator-15.2)
Otherwise, true if there exists an integer 0≤i<sizeof...(Views) such that bool(std::get<i>(x.*current_*) == std::get<i>(y.*current_*)) is true[.](#range.zip.iterator-15.2.sentence-1)
[*Note [1](#range.zip.iterator-note-1)*:
This allows zip_view to model [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]") when all constituent views model [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")[.](#range.zip.iterator-15.2.sentence-2)
— *end note*]
- [(15.3)](#range.zip.iterator-15.3)
Otherwise, false[.](#range.zip.iterator-15.3.sentence-1)
[🔗](#lib:operator%3c=%3e,izip_view::iterator)
`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](#range.zip.iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11760)
*Returns*: x.*current_* <=> y.*current_*[.](#range.zip.iterator-16.sentence-1)
[🔗](#lib:operator+,izip_view::iterator)
`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](#range.zip.iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11774)
*Effects*: Equivalent to:auto r = i;
r += n;return r;
[🔗](#lib:operator-,izip_view::iterator)
`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](#range.zip.iterator-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11791)
*Effects*: Equivalent to:auto r = i;
r -= n;return r;
[🔗](#lib:operator-,izip_view::iterator_)
`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](#range.zip.iterator-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11809)
Let *DIST*(i) be difference_type(std::get<i>(x.*current_*) - std::get<i>(y.*current_*))[.](#range.zip.iterator-19.sentence-1)
[20](#range.zip.iterator-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11812)
*Returns*: The value with the smallest absolute value among *DIST*(n) for all integers 0≤n<sizeof...(Views)[.](#range.zip.iterator-20.sentence-1)
[🔗](#lib:iter_move,izip_view::iterator)
`friend constexpr auto iter_move(const iterator& i) noexcept(see below);
`
[21](#range.zip.iterator-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11824)
*Effects*: Equivalent to:return *tuple-transform*(ranges::iter_move, i.*current_*);
[22](#range.zip.iterator-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11831)
*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>>> && ...)
[🔗](#lib:iter_swap,izip_view::iterator)
`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](#range.zip.iterator-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11849)
*Effects*: For every integer 0≤i<sizeof...(Views),
performs:ranges::iter_swap(std::get<i>(l.*current_*), std::get<i>(r.*current_*))
[24](#range.zip.iterator-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11857)
*Remarks*: The exception specification is equivalent to
the logical and of the following expressions:noexcept(ranges::iter_swap(std::get<i>(l.*current_*), std::get<i>(r.*current_*))) for every integer 0≤i<sizeof...(Views)[.](#range.zip.iterator-24.sentence-1)
#### [25.7.25.4](#range.zip.sentinel) Class template zip_view::*sentinel* [[range.zip.sentinel]](range.zip.sentinel)
[🔗](#lib:zip_view::sentinel)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")... Views>requires ([view](range.view#concept:view "25.4.5Views[range.view]")<Views> && ...) && (sizeof...(Views) > 0)template<bool Const>class zip_view<Views...>::*sentinel* { tuple<sentinel_t<*maybe-const*<Const, Views>>...> *end_*; // *exposition only*constexpr explicit *sentinel*(tuple<sentinel_t<*maybe-const*<Const, Views>>...> end); // *exposition only*public:*sentinel*() = default; 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>> && ...); 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); 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); 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); };}
[🔗](#lib:zip_view::sentinel,constructor)
`constexpr explicit sentinel(tuple<sentinel_t<maybe-const<Const, Views>>...> end);
`
[1](#range.zip.sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11910)
*Effects*: Initializes *end_* with end[.](#range.zip.sentinel-1.sentence-1)
[🔗](#lib:zip_view::sentinel,constructor_)
`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](#range.zip.sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11922)
*Effects*: Initializes *end_* with std::move(i.*end_*)[.](#range.zip.sentinel-2.sentence-1)
[🔗](#lib:operator==,zip_view::sentinel)
`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](#range.zip.sentinel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11936)
*Returns*: true if there exists an integer 0≤i<sizeof...(Views) such that bool(std::get<i>(x.*current_*) == std::get<i>(y.*end_*)) is true[.](#range.zip.sentinel-3.sentence-1)
Otherwise, false[.](#range.zip.sentinel-3.sentence-2)
[🔗](#lib:operator-,zip_view::sentinel)
`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](#range.zip.sentinel-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11954)
Let D be the return type[.](#range.zip.sentinel-4.sentence-1)
Let *DIST*(i) beD(std::get<i>(x.*current_*) - std::get<i>(y.*end_*))[.](#range.zip.sentinel-4.sentence-2)
[5](#range.zip.sentinel-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11959)
*Returns*: The value with the smallest absolute value among *DIST*(n) for all integers 0≤n<sizeof...(Views)[.](#range.zip.sentinel-5.sentence-1)
[🔗](#lib:operator-,zip_view::sentinel_)
`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](#range.zip.sentinel-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11975)
*Effects*: Equivalent to: return -(x - y);
### [25.7.26](#range.zip.transform) Zip transform view [[range.zip.transform]](range.zip.transform)
#### [25.7.26.1](#range.zip.transform.overview) Overview [[range.zip.transform.overview]](range.zip.transform.overview)
[1](#range.zip.transform.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11984)
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[.](#range.zip.transform.overview-1.sentence-1)
[2](#range.zip.transform.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11993)
The name views::zip_transform denotes
a customization point object ([[customization.point.object]](customization.point.object "16.3.3.3.5Customization Point Object types"))[.](#range.zip.transform.overview-2.sentence-1)
Let F be a subexpression, and
let Es... be a pack of subexpressions[.](#range.zip.transform.overview-2.sentence-2)
- [(2.1)](#range.zip.transform.overview-2.1)
If Es is an empty pack,
let FD be decay_t<decltype((F))>[.](#range.zip.transform.overview-2.1.sentence-1)
* [(2.1.1)](#range.zip.transform.overview-2.1.1)
If [move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13Concept move_­constructible[concept.moveconstructible]")<FD> &&[regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<FD&> is false, or
if decay_t<invoke_result_t<FD&>> is not an object type,views::zip_transform(F, Es...) is ill-formed.
* [(2.1.2)](#range.zip.transform.overview-2.1.2)
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)](#range.zip.transform.overview-2.2)
Otherwise, the expression views::zip_transform(F, Es...) is expression-equivalent to zip_transform_view(F, Es...)[.](#range.zip.transform.overview-2.2.sentence-1)
[3](#range.zip.transform.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12021)
[*Example [1](#range.zip.transform.overview-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](#range.zip.transform.view) Class template zip_transform_view [[range.zip.transform.view]](range.zip.transform.view)
[🔗](#lib:zip_transform_view_)
namespace std::ranges {template<[move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13Concept move_­constructible[concept.moveconstructible]") F, [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")... Views>requires ([view](range.view#concept:view "25.4.5Views[range.view]")<Views> && ...) && (sizeof...(Views) > 0) && is_object_v<F> &&[regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<F&, range_reference_t<Views>...> &&[*can-reference*](iterator.synopsis#concept:can-reference "24.2Header <iterator>&nbsp;synopsis[iterator.synopsis]")<invoke_result_t<F&, range_reference_t<Views>...>>class zip_transform_view : public view_interface<zip_transform_view<F, Views...>> {*movable-box*<F> *fun_*; // *exposition only* zip_view<Views...> *zip_*; // *exposition only*using *InnerView* = zip_view<Views...>; // *exposition only*template<bool Const>using *ziperator* = iterator_t<*maybe-const*<Const, *InnerView*>>; // *exposition only*template<bool Const>using *zentinel* = sentinel_t<*maybe-const*<Const, *InnerView*>>; // *exposition only*// [[range.zip.transform.iterator]](#range.zip.transform.iterator "25.7.26.3Class template zip_­transform_­view::iterator"), class template zip_transform_view::*iterator*template<bool> class *iterator*; // *exposition only*// [[range.zip.transform.sentinel]](#range.zip.transform.sentinel "25.7.26.4Class template zip_­transform_­view::sentinel"), class template zip_transform_view::*sentinel*template<bool> class *sentinel*; // *exposition only*public: zip_transform_view() = default; constexpr explicit zip_transform_view(F fun, Views... views); constexpr auto begin() { return *iterator*<false>(*this, *zip_*.begin()); }constexpr auto begin() constrequires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const *InnerView*> &&[regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<const F&, range_reference_t<const Views>...> {return *iterator*<true>(*this, *zip_*.begin()); }constexpr auto end() {if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<*InnerView*>) {return *iterator*<false>(*this, *zip_*.end()); } else {return *sentinel*<false>(*zip_*.end()); }}constexpr auto end() constrequires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const *InnerView*> &&[regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<const F&, range_reference_t<const Views>...> {if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<const *InnerView*>) {return *iterator*<true>(*this, *zip_*.end()); } else {return *sentinel*<true>(*zip_*.end()); }}constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<*InnerView*> {return *zip_*.size(); }constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const *InnerView*> {return *zip_*.size(); }}; template<class F, class... Rs> zip_transform_view(F, Rs&&...) -> zip_transform_view<F, views::all_t<Rs>...>;}
[🔗](#lib:zip_transform_view,constructor)
`constexpr explicit zip_transform_view(F fun, Views... views);
`
[1](#range.zip.transform.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12112)
*Effects*: Initializes *fun_* with std::move(fun) and*zip_* with std::move(views)...[.](#range.zip.transform.view-1.sentence-1)
#### [25.7.26.3](#range.zip.transform.iterator) Class template zip_transform_view::*iterator* [[range.zip.transform.iterator]](range.zip.transform.iterator)
[🔗](#lib:zip_transform_view::iterator)
namespace std::ranges {template<[move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13Concept move_­constructible[concept.moveconstructible]") F, [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")... Views>requires ([view](range.view#concept:view "25.4.5Views[range.view]")<Views> && ...) && (sizeof...(Views) > 0) && is_object_v<F> &&[regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<F&, range_reference_t<Views>...> &&[*can-reference*](iterator.synopsis#concept:can-reference "24.2Header <iterator>&nbsp;synopsis[iterator.synopsis]")<invoke_result_t<F&, range_reference_t<Views>...>>template<bool Const>class zip_transform_view<F, Views...>::*iterator* {using *Parent* = *maybe-const*<Const, zip_transform_view>; // *exposition only*using *Base* = *maybe-const*<Const, *InnerView*>; // *exposition only**Parent** *parent_* = nullptr; // *exposition only**ziperator*<Const> *inner_*; // *exposition only*constexpr *iterator*(*Parent*& parent, *ziperator*<Const> inner); // *exposition only*public:using iterator_category = *see below*; // not always presentusing iterator_concept = typename *ziperator*<Const>::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*<!Const> i)requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<*ziperator*<false>, *ziperator*<Const>>; constexpr decltype(auto) operator*() const noexcept(*see below*); constexpr *iterator*& operator++(); constexpr void operator++(int); constexpr *iterator* operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator* operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator+=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator-=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr decltype(auto) operator[](difference_type n) constrequires [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 [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*>; 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*>; 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 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>>; };}
[1](#range.zip.transform.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12180)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]")*iterator*::iterator_category is defined if and only if *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")[.](#range.zip.transform.iterator-1.sentence-1)
In that case,*iterator*::iterator_category is defined as follows:
- [(1.1)](#range.zip.transform.iterator-1.1)
Ifinvoke_result_t<*maybe-const*<Const, F>&, range_reference_t<*maybe-const*<Const, Views>>...> is not a reference,iterator_category denotes input_iterator_tag.
- [(1.2)](#range.zip.transform.iterator-1.2)
Otherwise, let Cs denote the pack of typesiterator_traits<iterator_t<*maybe-const*<Const, Views>>>::iterator_category.... * [(1.2.1)](#range.zip.transform.iterator-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)](#range.zip.transform.iterator-1.2.2)
Otherwise,
if ([derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<Cs, bidirectional_iterator_tag> && ...) is true,iterator_category denotes bidirectional_iterator_tag[.](#range.zip.transform.iterator-1.2.2.sentence-1)
* [(1.2.3)](#range.zip.transform.iterator-1.2.3)
Otherwise,
if ([derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<Cs, forward_iterator_tag> && ...) is true,iterator_category denotes forward_iterator_tag[.](#range.zip.transform.iterator-1.2.3.sentence-1)
* [(1.2.4)](#range.zip.transform.iterator-1.2.4)
Otherwise, iterator_category denotes input_iterator_tag[.](#range.zip.transform.iterator-1.2.4.sentence-1)
[🔗](#lib:zip_transform_view::iterator,constructor)
`constexpr iterator(Parent& parent, ziperator<Const> inner);
`
[2](#range.zip.transform.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12223)
*Effects*: Initializes *parent_* with addressof(parent) and*inner_* with std::move(inner)[.](#range.zip.transform.iterator-2.sentence-1)
[🔗](#lib:zip_transform_view::iterator,constructor_)
`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](#range.zip.transform.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12236)
*Effects*: Initializes *parent_* with i.*parent_* and*inner_* with std::move(i.*inner_*)[.](#range.zip.transform.iterator-3.sentence-1)
[🔗](#lib:operator*,zip_transform_view::iterator)
`constexpr decltype(auto) operator*() const noexcept(see below);
`
[4](#range.zip.transform.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12248)
*Effects*: Equivalent to:return apply([&](const auto&... iters) -> decltype(auto) {return invoke(**parent_*->*fun_*, *iters...);}, *inner_*.*current_*);
[5](#range.zip.transform.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12257)
*Remarks*: Let Is be the pack 0, 1, …, (sizeof...(Views) - 1)[.](#range.zip.transform.iterator-5.sentence-1)
The exception specification is equivalent to:noexcept(invoke(**parent_*->*fun_*, *std::get<Is>(*inner_*.*current_*)...))[.](#range.zip.transform.iterator-5.sentence-2)
[🔗](#lib:operator++,zip_transform_view::iterator)
`constexpr iterator& operator++();
`
[6](#range.zip.transform.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12270)
*Effects*: Equivalent to:++*inner_*;return *this;
[🔗](#lib:operator++,zip_transform_view::iterator_)
`constexpr void operator++(int);
`
[7](#range.zip.transform.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12285)
*Effects*: Equivalent to: ++*this[.](#range.zip.transform.iterator-7.sentence-1)
[🔗](#lib:operator++,zip_transform_view::iterator__)
`constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[8](#range.zip.transform.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12296)
*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,zip_transform_view::iterator)
`constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[9](#range.zip.transform.iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12312)
*Effects*: Equivalent to:--*inner_*;return *this;
[🔗](#lib:operator--,zip_transform_view::iterator_)
`constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[10](#range.zip.transform.iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12327)
*Effects*: Equivalent to:auto tmp = *this;--*this;return tmp;
[🔗](#lib:operator+=,zip_transform_view::iterator)
`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](#range.zip.transform.iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12344)
*Effects*: Equivalent to:*inner_* += x;return *this;
[🔗](#lib:operator+=,zip_transform_view::iterator_)
`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](#range.zip.transform.iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12360)
*Effects*: Equivalent to:*inner_* -= x;return *this;
[🔗](#lib:operator%5b%5d,zip_transform_view::iterator)
`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](#range.zip.transform.iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12376)
*Effects*: Equivalent to:return apply([&]<class... Is>(const Is&... iters) -> decltype(auto) {return invoke(**parent_*->*fun_*, iters[iter_difference_t<Is>(n)]...);}, *inner_*.*current_*);
[🔗](#lib:operator==,zip_transform_view::iterator)
`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](#range.zip.transform.iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12395)
Let *op* be the operator[.](#range.zip.transform.iterator-14.sentence-1)
[15](#range.zip.transform.iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12398)
*Effects*: Equivalent to:return x.*inner_* *op* y.*inner_*;
[🔗](#lib:operator+,zip_transform_view::iterator)
`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](#range.zip.transform.iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12413)
*Effects*: Equivalent to:return *iterator*(*i.*parent_*, i.*inner_* + n);
[🔗](#lib:operator-,zip_transform_view::iterator)
`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](#range.zip.transform.iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12426)
*Effects*: Equivalent to:return *iterator*(*i.*parent_*, i.*inner_* - n);
[🔗](#lib:operator-,zip_transform_view::iterator_)
`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](#range.zip.transform.iterator-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12439)
*Effects*: Equivalent to:return x.*inner_* - y.*inner_*;
#### [25.7.26.4](#range.zip.transform.sentinel) Class template zip_transform_view::*sentinel* [[range.zip.transform.sentinel]](range.zip.transform.sentinel)
[🔗](#lib:zip_transform_view::sentinel)
namespace std::ranges {template<[move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13Concept move_­constructible[concept.moveconstructible]") F, [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")... Views>requires ([view](range.view#concept:view "25.4.5Views[range.view]")<Views> && ...) && (sizeof...(Views) > 0) && is_object_v<F> &&[regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<F&, range_reference_t<Views>...> &&[*can-reference*](iterator.synopsis#concept:can-reference "24.2Header <iterator>&nbsp;synopsis[iterator.synopsis]")<invoke_result_t<F&, range_reference_t<Views>...>>template<bool Const>class zip_transform_view<F, Views...>::*sentinel* {*zentinel*<Const> *inner_*; // *exposition only*constexpr explicit *sentinel*(*zentinel*<Const> inner); // *exposition only*public:*sentinel*() = default; 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>>; 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); 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); };}
[🔗](#lib:zip_transform_view::sentinel,constructor)
`constexpr explicit sentinel(zentinel<Const> inner);
`
[1](#range.zip.transform.sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12487)
*Effects*: Initializes *inner_* with inner[.](#range.zip.transform.sentinel-1.sentence-1)
[🔗](#lib:zip_transform_view::sentinel,constructor_)
`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](#range.zip.transform.sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12499)
*Effects*: Initializes *inner_* with std::move(i.*inner_*)[.](#range.zip.transform.sentinel-2.sentence-1)
[🔗](#lib:operator==,zip_transform_view::sentinel)
`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](#range.zip.transform.sentinel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12512)
*Effects*: Equivalent to: return x.*inner_* == y.*inner_*;
[🔗](#lib:operator-,zip_transform_view::sentinel)
`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](#range.zip.transform.sentinel-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12530)
*Effects*: Equivalent to: return x.*inner_* - y.*inner_*;
### [25.7.27](#range.adjacent) Adjacent view [[range.adjacent]](range.adjacent)
#### [25.7.27.1](#range.adjacent.overview) Overview [[range.adjacent.overview]](range.adjacent.overview)
[1](#range.adjacent.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12539)
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[.](#range.adjacent.overview-1.sentence-1)
If the original view has fewer than N elements, the resulting view is empty[.](#range.adjacent.overview-1.sentence-2)
[2](#range.adjacent.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12547)
The name views::adjacent<N> denotes
a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.adjacent.overview-2.sentence-1)
Given a subexpression E and a constant expression N,
the expression views::adjacent<N>(E) is expression-equivalent to
- [(2.1)](#range.adjacent.overview-2.1)
((void)E, auto(views::empty<tuple<>>)) if N is equal to 0 anddecltype((E)) models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"),
- [(2.2)](#range.adjacent.overview-2.2)
otherwise, adjacent_view<views::all_t<decltype((E))>, N>(E)[.](#range.adjacent.overview-2.sentence-2)
[*Example [1](#range.adjacent.overview-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](#range.adjacent.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12572)
Define *REPEAT*(T, N) as a pack of N types,
each of which denotes the same type as T[.](#range.adjacent.overview-3.sentence-1)
#### [25.7.27.2](#range.adjacent.view) Class template adjacent_view [[range.adjacent.view]](range.adjacent.view)
[🔗](#lib:adjacent_view)
namespace std::ranges {template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") V, size_t N>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && (N > 0)class adjacent_view : public view_interface<adjacent_view<V, N>> { V *base_* = V(); // *exposition only*// [[range.adjacent.iterator]](#range.adjacent.iterator "25.7.27.3Class template adjacent_­view::iterator"), class template adjacent_view::*iterator*template<bool> class *iterator*; // *exposition only*// [[range.adjacent.sentinel]](#range.adjacent.sentinel "25.7.27.4Class template adjacent_­view::sentinel"), class template adjacent_view::*sentinel*template<bool> class *sentinel*; // *exposition only*struct *as-sentinel*{}; // *exposition only*public: adjacent_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> = default; constexpr explicit adjacent_view(V base); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr auto begin() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>) {return *iterator*<false>(ranges::begin(*base_*), ranges::end(*base_*)); }constexpr auto begin() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V> {return *iterator*<true>(ranges::begin(*base_*), ranges::end(*base_*)); }constexpr auto end() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>) {if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V>) {return *iterator*<false>(*as-sentinel*{}, ranges::begin(*base_*), ranges::end(*base_*)); } else {return *sentinel*<false>(ranges::end(*base_*)); }}constexpr auto end() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V> {if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<const V>) {return *iterator*<true>(*as-sentinel*{}, ranges::begin(*base_*), ranges::end(*base_*)); } else {return *sentinel*<true>(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>; 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>; };}
[🔗](#lib:adjacent_view,constructor)
`constexpr explicit adjacent_view(V base);
`
[1](#range.adjacent.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12642)
*Effects*: Initializes *base_* with std::move(base)[.](#range.adjacent.view-1.sentence-1)
[🔗](#lib:size,adjacent_view)
`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](#range.adjacent.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12654)
*Effects*: Equivalent to:using ST = decltype(ranges::size(*base_*));using CT = common_type_t<ST, size_t>;auto sz = static_cast<CT>(ranges::size(*base_*));
sz -= std::min<CT>(sz, N - 1);return static_cast<ST>(sz);
[🔗](#lib:reserve_hint,adjacent_view)
`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](#range.adjacent.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12673)
*Effects*: Equivalent to:using DT = range_difference_t<decltype((*base_*))>;using CT = common_type_t<DT, size_t>;auto sz = static_cast<CT>(ranges::reserve_hint(*base_*));
sz -= std::min<CT>(sz, N - 1);return *to-unsigned-like*(sz);
#### [25.7.27.3](#range.adjacent.iterator) Class template adjacent_view::*iterator* [[range.adjacent.iterator]](range.adjacent.iterator)
[🔗](#lib:adjacent_view::iterator)
namespace std::ranges {template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") V, size_t N>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && (N > 0)template<bool Const>class 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 only*constexpr *iterator*(iterator_t<*Base*> first, sentinel_t<*Base*> last); // *exposition only*constexpr *iterator*(*as-sentinel*, iterator_t<*Base*> first, iterator_t<*Base*> last); // *exposition only*public: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*<!Const> i)requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<V>, iterator_t<*Base*>>; constexpr auto operator*() const; constexpr *iterator*& operator++(); constexpr *iterator* operator++(int); constexpr *iterator*& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator* operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator+=(difference_type x)requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator-=(difference_type x)requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr auto operator[](difference_type n) constrequires [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); 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]")<iterator_t<*Base*>>; 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*>; 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 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*>>; 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](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<*Base*>>; };}
[1](#range.adjacent.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12753)
*iterator*::iterator_concept is defined as follows:
- [(1.1)](#range.adjacent.iterator-1.1)
If *Base* models [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes random_access_iterator_tag[.](#range.adjacent.iterator-1.1.sentence-1)
- [(1.2)](#range.adjacent.iterator-1.2)
Otherwise, if *Base* models [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes bidirectional_iterator_tag[.](#range.adjacent.iterator-1.2.sentence-1)
- [(1.3)](#range.adjacent.iterator-1.3)
Otherwise, iterator_concept denotes forward_iterator_tag[.](#range.adjacent.iterator-1.3.sentence-1)
[2](#range.adjacent.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12766)
If the invocation of any non-const member function of *iterator* exits via an exception, the *iterator* acquires a singular value[.](#range.adjacent.iterator-2.sentence-1)
[🔗](#lib:adjacent_view::iterator,constructor)
`constexpr iterator(iterator_t<Base> first, sentinel_t<Base> last);
`
[3](#range.adjacent.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12776)
*Postconditions*: *current_*[0] == first is true, and
for every integer 1≤i<N,*current_*[i] == ranges::next(*current_*[i-1], 1, last) is true[.](#range.adjacent.iterator-3.sentence-1)
[🔗](#lib:adjacent_view::iterator,constructor_)
`constexpr iterator(as-sentinel, iterator_t<Base> first, iterator_t<Base> last);
`
[4](#range.adjacent.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12790)
*Postconditions*: If *Base* does not model [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]"),
each element of *current_* is equal to *last*[.](#range.adjacent.iterator-4.sentence-1)
Otherwise, *current_*[N-1] == last is true, and
for every integer ‰¤i<(ˆ’1),*current_*[i] == ranges::prev(*current_*[i+1], 1, first) is true[.](#range.adjacent.iterator-4.sentence-2)
[🔗](#lib:adjacent_view::iterator,constructor__)
`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](#range.adjacent.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12807)
*Effects*: Initializes each element of *current_* with the corresponding element of i.*current_* as an xvalue[.](#range.adjacent.iterator-5.sentence-1)
[🔗](#lib:operator*,adjacent_view::iterator)
`constexpr auto operator*() const;
`
[6](#range.adjacent.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12819)
*Effects*: Equivalent to:return *tuple-transform*([](auto& i) -> decltype(auto) { return *i; }, *current_*);
[🔗](#lib:operator++,adjacent_view::iterator)
`constexpr iterator& operator++();
`
[7](#range.adjacent.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12833)
*Preconditions*: *current_*.back() is incrementable[.](#range.adjacent.iterator-7.sentence-1)
[8](#range.adjacent.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12837)
*Postconditions*: Each element of *current_* is equal to ranges::next(i),
where i is the value of that element before the call[.](#range.adjacent.iterator-8.sentence-1)
[9](#range.adjacent.iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12842)
*Returns*: *this[.](#range.adjacent.iterator-9.sentence-1)
[🔗](#lib:operator++,adjacent_view::iterator_)
`constexpr iterator operator++(int);
`
[10](#range.adjacent.iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12853)
*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,adjacent_view::iterator)
`constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[11](#range.adjacent.iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12869)
*Preconditions*: *current_*.front() is decrementable[.](#range.adjacent.iterator-11.sentence-1)
[12](#range.adjacent.iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12873)
*Postconditions*: Each element of *current_* is equal to ranges::prev(i),
where i is the value of that element before the call[.](#range.adjacent.iterator-12.sentence-1)
[13](#range.adjacent.iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12878)
*Returns*: *this[.](#range.adjacent.iterator-13.sentence-1)
[🔗](#lib:operator--,adjacent_view::iterator_)
`constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[14](#range.adjacent.iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12889)
*Effects*: Equivalent to:auto tmp = *this;--*this;return tmp;
[🔗](#lib:operator+=,adjacent_view::iterator)
`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](#range.adjacent.iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12906)
*Preconditions*: *current_*.back() + x has well-defined behavior[.](#range.adjacent.iterator-15.sentence-1)
[16](#range.adjacent.iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12910)
*Postconditions*: Each element of *current_* is equal to i + x,
where i is the value of that element before the call[.](#range.adjacent.iterator-16.sentence-1)
[17](#range.adjacent.iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12915)
*Returns*: *this[.](#range.adjacent.iterator-17.sentence-1)
[🔗](#lib:operator-=,adjacent_view::iterator)
`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](#range.adjacent.iterator-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12927)
*Preconditions*: *current_*.front() - x has well-defined behavior[.](#range.adjacent.iterator-18.sentence-1)
[19](#range.adjacent.iterator-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12931)
*Postconditions*: Each element of *current_* is equal to i - x,
where i is the value of that element before the call[.](#range.adjacent.iterator-19.sentence-1)
[20](#range.adjacent.iterator-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12936)
*Returns*: *this[.](#range.adjacent.iterator-20.sentence-1)
[🔗](#lib:operator%5b%5d,adjacent_view::iterator)
`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](#range.adjacent.iterator-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12948)
*Effects*: Equivalent to:return *tuple-transform*([&](auto& i) -> decltype(auto) { return i[n]; }, *current_*);
[🔗](#lib:operator==,adjacent_view::iterator)
`friend constexpr bool operator==(const iterator& x, const iterator& y);
`
[22](#range.adjacent.iterator-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12962)
*Returns*: x.*current_*.back() == y.*current_*.back()[.](#range.adjacent.iterator-22.sentence-1)
[🔗](#lib:operator%3c,adjacent_view::iterator)
`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](#range.adjacent.iterator-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12974)
*Returns*: x.*current_*.back() < y.*current_*.back()[.](#range.adjacent.iterator-23.sentence-1)
[🔗](#lib:operator%3e,adjacent_view::iterator)
`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](#range.adjacent.iterator-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12986)
*Effects*: Equivalent to: return y < x;
[🔗](#lib:operator%3c=,adjacent_view::iterator)
`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](#range.adjacent.iterator-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L12998)
*Effects*: Equivalent to: return !(y < x);
[🔗](#lib:operator%3e=,adjacent_view::iterator)
`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](#range.adjacent.iterator-26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13010)
*Effects*: Equivalent to: return !(x < y);
[🔗](#lib:operator%3c=%3e,adjacent_view::iterator)
`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](#range.adjacent.iterator-27)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13023)
*Returns*: x.*current_*.back() <=> y.*current_*.back()[.](#range.adjacent.iterator-27.sentence-1)
[🔗](#lib:operator+,adjacent_view::iterator)
`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](#range.adjacent.iterator-28)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13037)
*Effects*: Equivalent to:auto r = i;
r += n;return r;
[🔗](#lib:operator-,adjacent_view::iterator)
`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](#range.adjacent.iterator-29)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13054)
*Effects*: Equivalent to:auto r = i;
r -= n;return r;
[🔗](#lib:operator-,adjacent_view::iterator_)
`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](#range.adjacent.iterator-30)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13071)
*Effects*: Equivalent to:return x.*current_*.back() - y.*current_*.back();
[🔗](#lib:iter_move,adjacent_view::iterator)
`friend constexpr auto iter_move(const iterator& i) noexcept(see below);
`
[31](#range.adjacent.iterator-31)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13083)
*Effects*: Equivalent to:return *tuple-transform*(ranges::iter_move, i.*current_*);
[32](#range.adjacent.iterator-32)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13088)
*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*>>
[🔗](#lib:iter_swap,adjacent_view::iterator)
`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](#range.adjacent.iterator-33)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13104)
*Preconditions*: None of the iterators in l.*current_* is equal to
an iterator in r.*current_*[.](#range.adjacent.iterator-33.sentence-1)
[34](#range.adjacent.iterator-34)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13109)
*Effects*: For every integer 0≤i<N,
performsranges::iter_swap(l.*current_*[i], r.*current_*[i])[.](#range.adjacent.iterator-34.sentence-1)
[35](#range.adjacent.iterator-35)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13115)
*Remarks*: The exception specification is equivalent to:noexcept(ranges::iter_swap(declval<iterator_t<*Base*>>(), declval<iterator_t<*Base*>>()))
#### [25.7.27.4](#range.adjacent.sentinel) Class template adjacent_view::*sentinel* [[range.adjacent.sentinel]](range.adjacent.sentinel)
[🔗](#lib:adjacent_view::sentinel)
namespace std::ranges {template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") V, size_t N>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && (N > 0)template<bool Const>class adjacent_view<V, N>::*sentinel* {using *Base* = *maybe-const*<Const, V>; // *exposition only* sentinel_t<*Base*> *end_* = sentinel_t<*Base*>(); // *exposition only*constexpr explicit *sentinel*(sentinel_t<*Base*> end); // *exposition only*public:*sentinel*() = default; 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*>>; 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); 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); 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); };}
[🔗](#lib:adjacent_view::sentinel,constructor)
`constexpr explicit sentinel(sentinel_t<Base> end);
`
[1](#range.adjacent.sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13164)
*Effects*: Initializes *end_* with end[.](#range.adjacent.sentinel-1.sentence-1)
[🔗](#lib:adjacent_view::sentinel,constructor_)
`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](#range.adjacent.sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13176)
*Effects*: Initializes *end_* with std::move(i.*end_*)[.](#range.adjacent.sentinel-2.sentence-1)
[🔗](#lib:operator==,adjacent_view::sentinel)
`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](#range.adjacent.sentinel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13189)
*Effects*: Equivalent to: return x.*current_*.back() == y.*end_*;
[🔗](#lib:operator-,adjacent_view::sentinel)
`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](#range.adjacent.sentinel-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13203)
*Effects*: Equivalent to: return x.*current_*.back() - y.*end_*;
[🔗](#lib:operator-,adjacent_view::sentinel_)
`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](#range.adjacent.sentinel-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13217)
*Effects*: Equivalent to: return y.*end_* - x.*current_*.back();
### [25.7.28](#range.adjacent.transform) Adjacent transform view [[range.adjacent.transform]](range.adjacent.transform)
#### [25.7.28.1](#range.adjacent.transform.overview) Overview [[range.adjacent.transform.overview]](range.adjacent.transform.overview)
[1](#range.adjacent.transform.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13226)
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[.](#range.adjacent.transform.overview-1.sentence-1)
If the original view has fewer than N elements, the resulting view is empty[.](#range.adjacent.transform.overview-1.sentence-2)
[2](#range.adjacent.transform.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13234)
The name views::adjacent_transform<N> denotes
a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.adjacent.transform.overview-2.sentence-1)
Given subexpressions E and F and
a constant expression N:
- [(2.1)](#range.adjacent.transform.overview-2.1)
If N is equal to 0 anddecltype((E)) models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"),views::adjacent_transform<N>(E, F) is expression-equivalent to((void)E, views::zip_transform(F)),
except that the evaluations of E and F are
indeterminately sequenced[.](#range.adjacent.transform.overview-2.1.sentence-1)
- [(2.2)](#range.adjacent.transform.overview-2.2)
Otherwise,
the expression views::adjacent_transform<N>(E, F) is
expression-equivalent toadjacent_transform_view<views::all_t<decltype((E))>, decay_t<decltype((F))>, N>(E, F)[.](#range.adjacent.transform.overview-2.2.sentence-1)
[3](#range.adjacent.transform.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13255)
[*Example [1](#range.adjacent.transform.overview-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](#range.adjacent.transform.view) Class template adjacent_transform_view [[range.adjacent.transform.view]](range.adjacent.transform.view)
[🔗](#lib:adjacent_transform_view)
namespace std::ranges {template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") V, [move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13Concept move_­constructible[concept.moveconstructible]") F, size_t N>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && (N > 0) && is_object_v<F> &&[regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<F&, *REPEAT*(range_reference_t<V>, N)...> &&[*can-reference*](iterator.synopsis#concept:can-reference "24.2Header <iterator>&nbsp;synopsis[iterator.synopsis]")<invoke_result_t<F&, *REPEAT*(range_reference_t<V>, N)...>>class adjacent_transform_view : public view_interface<adjacent_transform_view<V, F, N>> {*movable-box*<F> *fun_*; // *exposition only* adjacent_view<V, N> *inner_*; // *exposition only*using *InnerView* = adjacent_view<V, N>; // *exposition only*template<bool Const>using *inner-iterator* = iterator_t<*maybe-const*<Const, *InnerView*>>; // *exposition only*template<bool Const>using *inner-sentinel* = sentinel_t<*maybe-const*<Const, *InnerView*>>; // *exposition only*// [[range.adjacent.transform.iterator]](#range.adjacent.transform.iterator "25.7.28.3Class template adjacent_­transform_­view::iterator"), class template adjacent_transform_view::*iterator*template<bool> class *iterator*; // *exposition only*// [[range.adjacent.transform.sentinel]](#range.adjacent.transform.sentinel "25.7.28.4Class template adjacent_­transform_­view::sentinel"), class template adjacent_transform_view::*sentinel*template<bool> class *sentinel*; // *exposition only*public: adjacent_transform_view() = default; constexpr explicit adjacent_transform_view(V base, F fun); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *inner_*.base(); }constexpr V base() && { return std::move(*inner_*).base(); }constexpr auto begin() {return *iterator*<false>(*this, *inner_*.begin()); }constexpr auto begin() constrequires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const *InnerView*> &&[regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<const F&, *REPEAT*(range_reference_t<const V>, N)...> {return *iterator*<true>(*this, *inner_*.begin()); }constexpr auto end() {if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<*InnerView*>) {return *iterator*<false>(*this, *inner_*.end()); } else {return *sentinel*<false>(*inner_*.end()); }}constexpr auto end() constrequires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const *InnerView*> &&[regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<const F&, *REPEAT*(range_reference_t<const V>, N)...> {if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<const *InnerView*>) {return *iterator*<true>(*this, *inner_*.end()); } else {return *sentinel*<true>(*inner_*.end()); }}constexpr auto size() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<*InnerView*> {return *inner_*.size(); }constexpr auto size() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const *InnerView*> {return *inner_*.size(); }constexpr auto reserve_hint() requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<*InnerView*> {return *inner_*.reserve_hint(); }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 *InnerView*> {return *inner_*.reserve_hint(); }};}
[🔗](#lib:adjacent_transform_view,constructor)
`constexpr explicit adjacent_transform_view(V base, F fun);
`
[1](#range.adjacent.transform.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13356)
*Effects*: Initializes *fun_* with std::move(fun) and*inner_* with std::move(base)[.](#range.adjacent.transform.view-1.sentence-1)
#### [25.7.28.3](#range.adjacent.transform.iterator) Class template adjacent_transform_view::*iterator* [[range.adjacent.transform.iterator]](range.adjacent.transform.iterator)
[🔗](#lib:adjacent_transform_view::iterator)
namespace std::ranges {template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") V, [move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13Concept move_­constructible[concept.moveconstructible]") F, size_t N>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && (N > 0) && is_object_v<F> &&[regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<F&, *REPEAT*(range_reference_t<V>, N)...> &&[*can-reference*](iterator.synopsis#concept:can-reference "24.2Header <iterator>&nbsp;synopsis[iterator.synopsis]")<invoke_result_t<F&, *REPEAT*(range_reference_t<V>, N)...>>template<bool Const>class adjacent_transform_view<V, F, N>::*iterator* {using *Parent* = *maybe-const*<Const, adjacent_transform_view>; // *exposition only*using *Base* = *maybe-const*<Const, V>; // *exposition only**Parent** *parent_* = nullptr; // *exposition only**inner-iterator*<Const> *inner_*; // *exposition only*constexpr *iterator*(*Parent*& parent, *inner-iterator*<Const> inner); // *exposition only*public:using iterator_category = *see below*; using iterator_concept = typename *inner-iterator*<Const>::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*<!Const> i)requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<*inner-iterator*<false>, *inner-iterator*<Const>>; constexpr decltype(auto) operator*() const noexcept(*see below*); constexpr *iterator*& operator++(); constexpr *iterator* operator++(int); constexpr *iterator*& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator* operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator+=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator-=(difference_type x) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr decltype(auto) operator[](difference_type n) constrequires [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); 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>>; 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*>; 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 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>>; };}
[1](#range.adjacent.transform.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13427)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") *iterator*::iterator_category is defined as follows:
- [(1.1)](#range.adjacent.transform.iterator-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[.](#range.adjacent.transform.iterator-1.1.sentence-1)
- [(1.2)](#range.adjacent.transform.iterator-1.2)
Otherwise, let C denote the typeiterator_traits<iterator_t<*Base*>>::iterator_category[.](#range.adjacent.transform.iterator-1.2.sentence-1)
* [(1.2.1)](#range.adjacent.transform.iterator-1.2.1)
If [derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<C, random_access_iterator_tag> is true,iterator_category denotes random_access_iterator_tag[.](#range.adjacent.transform.iterator-1.2.1.sentence-1)
* [(1.2.2)](#range.adjacent.transform.iterator-1.2.2)
Otherwise,
if [derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<C, bidirectional_iterator_tag> is true,iterator_category denotes bidirectional_iterator_tag[.](#range.adjacent.transform.iterator-1.2.2.sentence-1)
* [(1.2.3)](#range.adjacent.transform.iterator-1.2.3)
Otherwise,
if [derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<C, forward_iterator_tag> is true,iterator_category denotes forward_iterator_tag[.](#range.adjacent.transform.iterator-1.2.3.sentence-1)
* [(1.2.4)](#range.adjacent.transform.iterator-1.2.4)
Otherwise, iterator_category denotes input_iterator_tag[.](#range.adjacent.transform.iterator-1.2.4.sentence-1)
[🔗](#lib:adjacent_transform_view::iterator,constructor)
`constexpr iterator(Parent& parent, inner-iterator<Const> inner);
`
[2](#range.adjacent.transform.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13465)
*Effects*: Initializes *parent_* with addressof(parent) and*inner_* with std::move(inner)[.](#range.adjacent.transform.iterator-2.sentence-1)
[🔗](#lib:adjacent_transform_view::iterator,constructor_)
`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](#range.adjacent.transform.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13478)
*Effects*: Initializes *parent_* with i.*parent_* and*inner_* with std::move(i.*inner_*)[.](#range.adjacent.transform.iterator-3.sentence-1)
[🔗](#lib:operator*,adjacent_transform_view::iterator)
`constexpr decltype(auto) operator*() const noexcept(see below);
`
[4](#range.adjacent.transform.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13490)
*Effects*: Equivalent to:return apply([&](const auto&... iters) -> decltype(auto) {return invoke(**parent_*->*fun_*, *iters...);}, *inner_*.*current_*);
[5](#range.adjacent.transform.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13499)
*Remarks*: Let Is be the pack 0, 1, …, (N - 1)[.](#range.adjacent.transform.iterator-5.sentence-1)
The exception specification is equivalent to:noexcept(invoke(**parent_*->*fun_*, *std::get<Is>(*inner_*.*current_*)...))
[🔗](#lib:operator++,adjacent_transform_view::iterator)
`constexpr iterator& operator++();
`
[6](#range.adjacent.transform.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13514)
*Effects*: Equivalent to:++*inner_*;return *this;
[🔗](#lib:operator++,adjacent_transform_view::iterator_)
`constexpr iterator operator++(int);
`
[7](#range.adjacent.transform.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13529)
*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,adjacent_transform_view::iterator)
`constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[8](#range.adjacent.transform.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13545)
*Effects*: Equivalent to:--*inner_*;return *this;
[🔗](#lib:operator--,adjacent_transform_view::iterator_)
`constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[9](#range.adjacent.transform.iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13560)
*Effects*: Equivalent to:auto tmp = *this;--*this;return tmp;
[🔗](#lib:operator+=,adjacent_transform_view::iterator)
`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](#range.adjacent.transform.iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13576)
*Effects*: Equivalent to:*inner_* += x;return *this;
[🔗](#lib:operator-=,adjacent_transform_view::iterator)
`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](#range.adjacent.transform.iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13591)
*Effects*: Equivalent to:*inner_* -= x;return *this;
[🔗](#lib:operator%5b%5d,adjacent_transform_view::iterator)
`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](#range.adjacent.transform.iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13607)
*Effects*: Equivalent to:return apply([&](const auto&... iters) -> decltype(auto) {return invoke(**parent_*->*fun_*, iters[n]...);}, *inner_*.*current_*);
[🔗](#lib:operator==,adjacent_transform_view::iterator)
`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](#range.adjacent.transform.iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13633)
Let *op* be the operator[.](#range.adjacent.transform.iterator-13.sentence-1)
[14](#range.adjacent.transform.iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13636)
*Effects*: Equivalent to: return x.*inner_* *op* y.*inner_*;
[🔗](#lib:operator+,adjacent_transform_view::iterator)
`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](#range.adjacent.transform.iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13650)
*Effects*: Equivalent to: return *iterator*(*i.*parent_*, i.*inner_* + n);
[🔗](#lib:operator-,adjacent_transform_view::iterator)
`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](#range.adjacent.transform.iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13662)
*Effects*: Equivalent to: return *iterator*(*i.*parent_*, i.*inner_* - n);
[🔗](#lib:operator-,adjacent_transform_view::iterator_)
`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](#range.adjacent.transform.iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13674)
*Effects*: Equivalent to: return x.*inner_* - y.*inner_*;
#### [25.7.28.4](#range.adjacent.transform.sentinel) Class template adjacent_transform_view::*sentinel* [[range.adjacent.transform.sentinel]](range.adjacent.transform.sentinel)
[🔗](#lib:adjacent_transform_view::sentinel)
namespace std::ranges {template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") V, [move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13Concept move_­constructible[concept.moveconstructible]") F, size_t N>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && (N > 0) && is_object_v<F> &&[regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3Concept regular_­invocable[concept.regularinvocable]")<F&, *REPEAT*(range_reference_t<V>, N)...> &&[*can-reference*](iterator.synopsis#concept:can-reference "24.2Header <iterator>&nbsp;synopsis[iterator.synopsis]")<invoke_result_t<F&, *REPEAT*(range_reference_t<V>, N)...>>template<bool Const>class adjacent_transform_view<V, F, N>::*sentinel* {*inner-sentinel*<Const> *inner_*; // *exposition only*constexpr explicit *sentinel*(*inner-sentinel*<Const> inner); // *exposition only*public:*sentinel*() = default; 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>>; 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); template<bool OtherConst>requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<*inner-sentinel*<Const>, *inner-iterator*<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]")<*inner-sentinel*<Const>, *inner-iterator*<OtherConst>>friend constexpr range_difference_t<*maybe-const*<OtherConst, *InnerView*>>operator-(const *sentinel*& x, const *iterator*<OtherConst>& y); };}
[🔗](#lib:adjacent_transform_view::sentinel,constructor)
`constexpr explicit sentinel(inner-sentinel<Const> inner);
`
[1](#range.adjacent.transform.sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13721)
*Effects*: Initializes *inner_* with inner[.](#range.adjacent.transform.sentinel-1.sentence-1)
[🔗](#lib:adjacent_transform_view::sentinel,constructor_)
`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](#range.adjacent.transform.sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13733)
*Effects*: Initializes *inner_* with std::move(i.*inner_*)[.](#range.adjacent.transform.sentinel-2.sentence-1)
[🔗](#lib:operator==,adjacent_transform_view::sentinel)
`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](#range.adjacent.transform.sentinel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13746)
*Effects*: Equivalent to: return x.*inner_* == y.*inner_*;
[🔗](#lib:operator-,adjacent_transform_view::sentinel)
`template<bool OtherConst>
requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<inner-sentinel<Const>, inner-iterator<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]")<inner-sentinel<Const>, inner-iterator<OtherConst>>
friend constexpr range_difference_t<maybe-const<OtherConst, InnerView>>
operator-(const sentinel& x, const iterator<OtherConst>& y);
`
[4](#range.adjacent.transform.sentinel-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13765)
*Effects*: Equivalent to: return x.*inner_* - y.*inner_*;
### [25.7.29](#range.chunk) Chunk view [[range.chunk]](range.chunk)
#### [25.7.29.1](#range.chunk.overview) Overview [[range.chunk.overview]](range.chunk.overview)
[1](#range.chunk.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13774)
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[.](#range.chunk.overview-1.sentence-1)
The last view in the range can have fewer than N elements[.](#range.chunk.overview-1.sentence-2)
[2](#range.chunk.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13781)
The name views::chunk denotes
a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.chunk.overview-2.sentence-1)
Given subexpressions E and N,
the expression views::chunk(E, N) is expression-equivalent tochunk_view(E, N)[.](#range.chunk.overview-2.sentence-2)
[*Example [1](#range.chunk.overview-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](#range.chunk.view.input) Class template chunk_view for input ranges [[range.chunk.view.input]](range.chunk.view.input)
[🔗](#lib:chunk_view)
namespace std::ranges {template<class I>constexpr I *div-ceil*(I num, I denom) { // *exposition only* I r = num / denom; if (num % denom)++r; return r; }template<[view](range.view#concept:view "25.4.5Views[range.view]") V>requires [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<V>class chunk_view : public view_interface<chunk_view<V>> { V *base_*; // *exposition only* range_difference_t<V> *n_*; // *exposition only* range_difference_t<V> *remainder_* = 0; // *exposition only**non-propagating-cache*<iterator_t<V>> *current_*; // *exposition only*// [[range.chunk.outer.iter]](#range.chunk.outer.iter "25.7.29.3Class chunk_­view::outer-iterator"), class chunk_view::*outer-iterator*class *outer-iterator*; // *exposition only*// [[range.chunk.inner.iter]](#range.chunk.inner.iter "25.7.29.5Class chunk_­view::inner-iterator"), class chunk_view::*inner-iterator*class *inner-iterator*; // *exposition only*public:constexpr explicit chunk_view(V base, range_difference_t<V> n); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { 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](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>; 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>; }; template<class R> chunk_view(R&&, range_difference_t<R>) -> chunk_view<views::all_t<R>>;}
[🔗](#lib:chunk_view,constructor)
`constexpr explicit chunk_view(V base, range_difference_t<V> n);
`
[1](#range.chunk.view.input-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13861)
*Preconditions*: n > 0 is true[.](#range.chunk.view.input-1.sentence-1)
[2](#range.chunk.view.input-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13865)
*Effects*: Initializes *base_* with std::move(base) and*n_* with n[.](#range.chunk.view.input-2.sentence-1)
[🔗](#lib:begin,chunk_view)
`constexpr outer-iterator begin();
`
[3](#range.chunk.view.input-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13877)
*Effects*: Equivalent to:*current_* = ranges::begin(*base_*);*remainder_* = *n_*;return *outer-iterator*(*this);
[🔗](#lib:end,chunk_view)
`constexpr default_sentinel_t end() const noexcept;
`
[4](#range.chunk.view.input-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13893)
*Returns*: default_sentinel[.](#range.chunk.view.input-4.sentence-1)
[🔗](#lib:size,chunk_view)
`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](#range.chunk.view.input-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13905)
*Effects*: Equivalent to:return *to-unsigned-like*(*div-ceil*(ranges::distance(*base_*), *n_*));
[🔗](#lib:reserve_hint,chunk_view)
`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](#range.chunk.view.input-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13920)
*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](#range.chunk.outer.iter) Class chunk_view::*outer-iterator* [[range.chunk.outer.iter]](range.chunk.outer.iter)
[🔗](#lib:chunk_view::outer-iterator)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V>requires [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<V>class chunk_view<V>::*outer-iterator* { chunk_view* *parent_*; // *exposition only*constexpr explicit *outer-iterator*(chunk_view& parent); // *exposition only*public:using iterator_concept = input_iterator_tag; using difference_type = range_difference_t<V>; // [[range.chunk.outer.value]](#range.chunk.outer.value "25.7.29.4Class chunk_­view::outer-iterator::value_­type"), 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](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>; 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>>; };}
[🔗](#lib:chunk_view::outer-iterator,constructor)
`constexpr explicit outer-iterator(chunk_view& parent);
`
[1](#range.chunk.outer.iter-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13971)
*Effects*: Initializes *parent_* with addressof(parent)[.](#range.chunk.outer.iter-1.sentence-1)
[🔗](#lib:operator*,chunk_view::outer-iterator)
`constexpr value_type operator*() const;
`
[2](#range.chunk.outer.iter-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13982)
*Preconditions*: *this == default_sentinel is false[.](#range.chunk.outer.iter-2.sentence-1)
[3](#range.chunk.outer.iter-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13986)
*Returns*: value_type(**parent_*)[.](#range.chunk.outer.iter-3.sentence-1)
[🔗](#lib:operator++,chunk_view::outer-iterator)
`constexpr outer-iterator& operator++();
`
[4](#range.chunk.outer.iter-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L13997)
*Preconditions*: *this == default_sentinel is false[.](#range.chunk.outer.iter-4.sentence-1)
[5](#range.chunk.outer.iter-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14001)
*Effects*: Equivalent to:ranges::advance(**parent_*->*current_*, *parent_*->*remainder_*, ranges::end(*parent_*->*base_*));*parent_*->*remainder_* = *parent_*->*n_*;return *this;
[🔗](#lib:operator++,chunk_view::outer-iterator_)
`constexpr void operator++(int);
`
[6](#range.chunk.outer.iter-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14017)
*Effects*: Equivalent to ++*this[.](#range.chunk.outer.iter-6.sentence-1)
[🔗](#lib:operator==,chunk_view::outer-iterator)
`friend constexpr bool operator==(const outer-iterator& x, default_sentinel_t);
`
[7](#range.chunk.outer.iter-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14028)
*Effects*: Equivalent to:return *x.*parent_*->*current_* == ranges::end(x.*parent_*->*base_*) && x.*parent_*->*remainder_* != 0;
[🔗](#lib:operator-,chunk_view::outer-iterator)
`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](#range.chunk.outer.iter-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14043)
*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;
[🔗](#lib:operator-,chunk_view::outer-iterator_)
`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](#range.chunk.outer.iter-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14062)
*Effects*: Equivalent to: return -(y - x);
#### [25.7.29.4](#range.chunk.outer.value) Class chunk_view::*outer-iterator*::value_type [[range.chunk.outer.value]](range.chunk.outer.value)
[🔗](#lib:chunk_view::outer-iterator::value_type)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V>requires [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<V>struct chunk_view<V>::*outer-iterator*::value_type : view_interface<value_type> {private: chunk_view* *parent_*; // *exposition only*constexpr explicit value_type(chunk_view& parent); // *exposition only*public:constexpr *inner-iterator* begin() const noexcept; constexpr default_sentinel_t end() const noexcept; constexpr auto size() constrequires [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>>; constexpr auto reserve_hint() const noexcept; };}
[🔗](#lib:chunk_view::outer-iterator::value_type,constructor)
`constexpr explicit value_type(chunk_view& parent);
`
[1](#range.chunk.outer.value-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14098)
*Effects*: Initializes *parent_* with addressof(parent)[.](#range.chunk.outer.value-1.sentence-1)
[🔗](#lib:begin,chunk_view::outer-iterator::value_type)
`constexpr inner-iterator begin() const noexcept;
`
[2](#range.chunk.outer.value-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14109)
*Returns*: *inner-iterator*(**parent_*)[.](#range.chunk.outer.value-2.sentence-1)
[🔗](#lib:end,chunk_view::outer-iterator::value_type)
`constexpr default_sentinel_t end() const noexcept;
`
[3](#range.chunk.outer.value-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14120)
*Returns*: default_sentinel[.](#range.chunk.outer.value-3.sentence-1)
[🔗](#lib:size,chunk_view::outer-iterator::value_type)
`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](#range.chunk.outer.value-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14132)
*Effects*: Equivalent to:return *to-unsigned-like*(ranges::min(*parent_*->*remainder_*,
ranges::end(*parent_*->*base_*) - **parent_*->*current_*));
[🔗](#lib:reserve_hint,chunk_view::outer-iterator::value_type)
`constexpr auto reserve_hint() const noexcept;
`
[5](#range.chunk.outer.value-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14147)
*Effects*: Equivalent to:return *to-unsigned-like*(*parent_*->*remainder_*);
#### [25.7.29.5](#range.chunk.inner.iter) Class chunk_view::*inner-iterator* [[range.chunk.inner.iter]](range.chunk.inner.iter)
[🔗](#lib:chunk_view::inner-iterator)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V>requires [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<V>class chunk_view<V>::*inner-iterator* { chunk_view* *parent_*; // *exposition only*constexpr explicit *inner-iterator*(chunk_view& parent) noexcept; // *exposition only*public:using iterator_concept = input_iterator_tag; using difference_type = range_difference_t<V>; using value_type = range_value_t<V>; *inner-iterator*(*inner-iterator*&&) = default; *inner-iterator*& operator=(*inner-iterator*&&) = default; constexpr const iterator_t<V>& base() const &; constexpr range_reference_t<V> 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](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<V>, iterator_t<V>>; 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>>; friend constexpr range_rvalue_reference_t<V> 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](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<V>>; };}
[🔗](#lib:chunk_view::inner-iterator,constructor)
`constexpr explicit inner-iterator(chunk_view& parent) noexcept;
`
[1](#range.chunk.inner.iter-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14204)
*Effects*: Initializes *parent_* with addressof(parent)[.](#range.chunk.inner.iter-1.sentence-1)
[🔗](#lib:base,chunk_view::inner-iterator)
`constexpr const iterator_t<V>& base() const &;
`
[2](#range.chunk.inner.iter-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14215)
*Effects*: Equivalent to: return **parent_*->*current_*;
[🔗](#lib:operator*,chunk_view::inner-iterator)
`constexpr range_reference_t<V> operator*() const;
`
[3](#range.chunk.inner.iter-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14226)
*Preconditions*: *this == default_sentinel is false[.](#range.chunk.inner.iter-3.sentence-1)
[4](#range.chunk.inner.iter-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14230)
*Effects*: Equivalent to: return ***parent_*->*current_*;
[🔗](#lib:operator++,chunk_view::inner-iterator)
`constexpr inner-iterator& operator++();
`
[5](#range.chunk.inner.iter-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14241)
*Preconditions*: *this == default_sentinel is false[.](#range.chunk.inner.iter-5.sentence-1)
[6](#range.chunk.inner.iter-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14245)
*Effects*: Equivalent to:++**parent_*->*current_*;if (**parent_*->*current_* == ranges::end(*parent_*->*base_*))*parent_*->*remainder_* = 0;else--*parent_*->*remainder_*;return *this;
[🔗](#lib:operator++,chunk_view::inner-iterator_)
`constexpr void operator++(int);
`
[7](#range.chunk.inner.iter-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14264)
*Effects*: Equivalent to ++*this[.](#range.chunk.inner.iter-7.sentence-1)
[🔗](#lib:operator==,chunk_view::inner-iterator)
`friend constexpr bool operator==(const inner-iterator& x, default_sentinel_t);
`
[8](#range.chunk.inner.iter-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14275)
*Returns*: x.*parent_*->*remainder_* == 0[.](#range.chunk.inner.iter-8.sentence-1)
[🔗](#lib:operator-,chunk_view::inner-iterator)
`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](#range.chunk.inner.iter-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14287)
*Effects*: Equivalent to:return ranges::min(x.*parent_*->*remainder_*,
ranges::end(x.*parent_*->*base_*) - *x.*parent_*->*current_*);
[🔗](#lib:operator-,chunk_view::inner-iterator_)
`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](#range.chunk.inner.iter-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14303)
*Effects*: Equivalent to: return -(y - x);
[🔗](#lib:iter_move,chunk_view::inner-iterator)
`friend constexpr range_rvalue_reference_t<V> iter_move(const inner-iterator& i)
noexcept(noexcept(ranges::iter_move(*i.parent_->current_)));
`
[11](#range.chunk.inner.iter-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14315)
*Effects*: Equivalent to: return ranges::iter_move(*i.*parent_*->*current_*);
[🔗](#lib:iter_swap,chunk_view::inner-iterator)
`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](#range.chunk.inner.iter-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14328)
*Effects*: Equivalent to: ranges::iter_swap(*x.*parent_*->*current_*, *y.*parent_*->*current_*);
#### [25.7.29.6](#range.chunk.view.fwd) Class template chunk_view for forward ranges [[range.chunk.view.fwd]](range.chunk.view.fwd)
[🔗](#lib:chunk_view_)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V>requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>class chunk_view<V> : public view_interface<chunk_view<V>> { V *base_*; // *exposition only* range_difference_t<V> *n_*; // *exposition only*// [[range.chunk.fwd.iter]](#range.chunk.fwd.iter "25.7.29.7Class template chunk_­view::iterator for forward ranges"), class template chunk_view::*iterator*template<bool> class *iterator*; // *exposition only*public:constexpr explicit chunk_view(V base, range_difference_t<V> n); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr auto begin() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>) {return *iterator*<false>(this, ranges::begin(*base_*)); }constexpr auto begin() const requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const V> {return *iterator*<true>(this, ranges::begin(*base_*)); }constexpr auto end() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>) {if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V> && [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>) {auto missing = (*n_* - ranges::distance(*base_*) % *n_*) % *n_*; return *iterator*<false>(this, ranges::end(*base_*), missing); } else if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V> && ![bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<V>) {return *iterator*<false>(this, ranges::end(*base_*)); } else {return default_sentinel; }}constexpr auto end() const requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const V> {if constexpr ([common_range](range.refinements#concept:common_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>) {auto missing = (*n_* - ranges::distance(*base_*) % *n_*) % *n_*; return *iterator*<true>(this, ranges::end(*base_*), missing); } else if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<const V> && ![bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<const V>) {return *iterator*<true>(this, ranges::end(*base_*)); } else {return 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>; 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>; };}
[🔗](#lib:chunk_view,constructor_)
`constexpr explicit chunk_view(V base, range_difference_t<V> n);
`
[1](#range.chunk.view.fwd-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14400)
*Preconditions*: n > 0 is true[.](#range.chunk.view.fwd-1.sentence-1)
[2](#range.chunk.view.fwd-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14404)
*Effects*: Initializes *base_* with std::move(base) and*n_* with n[.](#range.chunk.view.fwd-2.sentence-1)
[🔗](#lib:size,chunk_view_)
`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](#range.chunk.view.fwd-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14417)
*Effects*: Equivalent to:return *to-unsigned-like*(*div-ceil*(ranges::distance(*base_*), *n_*));
[🔗](#lib:reserve_hint,chunk_view_)
`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](#range.chunk.view.fwd-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14432)
*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](#range.chunk.fwd.iter) Class template chunk_view::*iterator* for forward ranges [[range.chunk.fwd.iter]](range.chunk.fwd.iter)
[🔗](#lib:chunk_view::iterator)
namespace std::ranges {template<[view](range.view#concept:view "25.4.5Views[range.view]") V>requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>template<bool Const>class chunk_view<V>::*iterator* {using *Parent* = *maybe-const*<Const, chunk_view>; // *exposition only*using *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 only*constexpr *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*<!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*>>; constexpr iterator_t<*Base*> base() const; constexpr value_type operator*() const; constexpr *iterator*& operator++(); constexpr *iterator* operator++(int); constexpr *iterator*& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator* operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator+=(difference_type x)requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator-=(difference_type x)requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr value_type operator[](difference_type n) constrequires [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); friend constexpr bool operator==(const *iterator*& x, default_sentinel_t); 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]")<iterator_t<*Base*>>; 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*>; 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 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*>>; 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*>>; 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*>>; };}
[1](#range.chunk.fwd.iter-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14521)
*iterator*::iterator_concept is defined as follows:
- [(1.1)](#range.chunk.fwd.iter-1.1)
If *Base* models [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes random_access_iterator_tag[.](#range.chunk.fwd.iter-1.1.sentence-1)
- [(1.2)](#range.chunk.fwd.iter-1.2)
Otherwise, if *Base* models [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes bidirectional_iterator_tag[.](#range.chunk.fwd.iter-1.2.sentence-1)
- [(1.3)](#range.chunk.fwd.iter-1.3)
Otherwise, iterator_concept denotes forward_iterator_tag[.](#range.chunk.fwd.iter-1.3.sentence-1)
[🔗](#lib:chunk_view::iterator,constructor)
`constexpr iterator(Parent* parent, iterator_t<Base> current,
range_difference_t<Base> missing = 0);
`
[2](#range.chunk.fwd.iter-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14541)
*Effects*: Initializes *current_* with current,*end_* with ranges::end(parent->*base_*),*n_* with parent->*n_*, and*missing_* with missing[.](#range.chunk.fwd.iter-2.sentence-1)
[🔗](#lib:chunk_view::iterator,constructor_)
`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](#range.chunk.fwd.iter-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14557)
*Effects*: Initializes *current_* with std::move(i.*current_*),*end_* with std::move(i.*end_*),*n_* with i.*n_*, and*missing_* with i.*missing_*[.](#range.chunk.fwd.iter-3.sentence-1)
[🔗](#lib:base,chunk_view::iterator)
`constexpr iterator_t<Base> base() const;
`
[4](#range.chunk.fwd.iter-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14571)
*Returns*: *current_*[.](#range.chunk.fwd.iter-4.sentence-1)
[🔗](#lib:operator*,chunk_view::iterator)
`constexpr value_type operator*() const;
`
[5](#range.chunk.fwd.iter-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14582)
*Preconditions*: *current_* != *end_* is true[.](#range.chunk.fwd.iter-5.sentence-1)
[6](#range.chunk.fwd.iter-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14586)
*Returns*: views::take(subrange(*current_*, *end_*), *n_*)[.](#range.chunk.fwd.iter-6.sentence-1)
[🔗](#lib:operator++,chunk_view::iterator)
`constexpr iterator& operator++();
`
[7](#range.chunk.fwd.iter-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14597)
*Preconditions*: *current_* != *end_* is true[.](#range.chunk.fwd.iter-7.sentence-1)
[8](#range.chunk.fwd.iter-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14601)
*Effects*: Equivalent to:*missing_* = ranges::advance(*current_*, *n_*, *end_*);return *this;
[🔗](#lib:operator++,chunk_view::iterator_)
`constexpr iterator operator++(int);
`
[9](#range.chunk.fwd.iter-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14616)
*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,chunk_view::iterator)
`constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[10](#range.chunk.fwd.iter-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14632)
*Effects*: Equivalent to:ranges::advance(*current_*, *missing_* - *n_*);*missing_* = 0;return *this;
[🔗](#lib:operator--,chunk_view::iterator_)
`constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[11](#range.chunk.fwd.iter-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14648)
*Effects*: Equivalent to:auto tmp = *this;--*this;return tmp;
[🔗](#lib:operator+=,chunk_view::iterator)
`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](#range.chunk.fwd.iter-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14665)
*Preconditions*: If x is positive,ranges::distance(*current_*, *end_*) > *n_* * (x - 1) is true[.](#range.chunk.fwd.iter-12.sentence-1)
[*Note [1](#range.chunk.fwd.iter-note-1)*:
If x is negative, the *Effects* paragraph implies a precondition[.](#range.chunk.fwd.iter-12.sentence-2)
— *end note*]
[13](#range.chunk.fwd.iter-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14674)
*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;
[🔗](#lib:operator-=,chunk_view::iterator)
`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](#range.chunk.fwd.iter-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14696)
*Effects*: Equivalent to: return *this += -x;
[🔗](#lib:operator%5b%5d,chunk_view::iterator)
`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](#range.chunk.fwd.iter-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14708)
*Returns*: *(*this + n)[.](#range.chunk.fwd.iter-15.sentence-1)
[🔗](#lib:operator-=,chunk_view::iterator_)
`friend constexpr bool operator==(const iterator& x, const iterator& y);
`
[16](#range.chunk.fwd.iter-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14719)
*Returns*: x.*current_* == y.*current_*[.](#range.chunk.fwd.iter-16.sentence-1)
[🔗](#lib:operator==,chunk_view::iterator)
`friend constexpr bool operator==(const iterator& x, default_sentinel_t);
`
[17](#range.chunk.fwd.iter-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14730)
*Returns*: x.*current_* == x.*end_*[.](#range.chunk.fwd.iter-17.sentence-1)
[🔗](#lib:operator%3c,chunk_view::iterator)
`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](#range.chunk.fwd.iter-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14742)
*Returns*: x.*current_* < y.*current_*[.](#range.chunk.fwd.iter-18.sentence-1)
[🔗](#lib:operator%3e,chunk_view::iterator)
`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](#range.chunk.fwd.iter-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14754)
*Effects*: Equivalent to: return y < x;
[🔗](#lib:operator%3c=,chunk_view::iterator)
`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](#range.chunk.fwd.iter-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14766)
*Effects*: Equivalent to: return !(y < x);
[🔗](#lib:operator%3e=,chunk_view::iterator)
`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](#range.chunk.fwd.iter-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14778)
*Effects*: Equivalent to: return !(x < y);
[🔗](#lib:operator%3c=%3e,chunk_view::iterator)
`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](#range.chunk.fwd.iter-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14791)
*Returns*: x.*current_* <=> y.*current_*[.](#range.chunk.fwd.iter-22.sentence-1)
[🔗](#lib:operator+,chunk_view::iterator)
`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](#range.chunk.fwd.iter-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14805)
*Effects*: Equivalent to:auto r = i;
r += n;return r;
[🔗](#lib:operator-,chunk_view::iterator)
`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](#range.chunk.fwd.iter-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14822)
*Effects*: Equivalent to:auto r = i;
r -= n;return r;
[🔗](#lib:operator-,chunk_view::iterator_)
`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](#range.chunk.fwd.iter-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14839)
*Returns*: (x.*current_* - y.*current_* + x.*missing_* - y.*missing_*) / x.*n_*[.](#range.chunk.fwd.iter-25.sentence-1)
[🔗](#lib:operator-,chunk_view::iterator__)
`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](#range.chunk.fwd.iter-26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14851)
*Returns*: *div-ceil*(x.*end_* - x.*current_*, x.*n_*)[.](#range.chunk.fwd.iter-26.sentence-1)
[🔗](#lib:operator-,chunk_view::iterator___)
`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](#range.chunk.fwd.iter-27)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14863)
*Effects*: Equivalent to: return -(y - x);
### [25.7.30](#range.slide) Slide view [[range.slide]](range.slide)
#### [25.7.30.1](#range.slide.overview) Overview [[range.slide.overview]](range.slide.overview)
[1](#range.slide.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14872)
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[.](#range.slide.overview-1.sentence-1)
If the original view has fewer than N elements,
the resulting view is empty[.](#range.slide.overview-1.sentence-2)
[2](#range.slide.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14882)
The name views::slide denotes
a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.slide.overview-2.sentence-1)
Given subexpressions E and N,
the expression views::slide(E, N) is expression-equivalent toslide_view(E, N)[.](#range.slide.overview-2.sentence-2)
[*Example [1](#range.slide.overview-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](#range.slide.view) Class template slide_view [[range.slide.view]](range.slide.view)
[🔗](#lib:slide_view)
namespace std::ranges {template<class V>concept [*slide-caches-nothing*](#concept:slide-caches-nothing "25.7.30.2Class template slide_­view[range.slide.view]") = [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<V> && [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V>; // *exposition only*template<class V>concept [*slide-caches-last*](#concept:slide-caches-last "25.7.30.2Class template slide_­view[range.slide.view]") = // *exposition only*![*slide-caches-nothing*](#concept:slide-caches-nothing "25.7.30.2Class template slide_­view[range.slide.view]")<V> && [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<V> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V>; template<class V>concept [*slide-caches-first*](#concept:slide-caches-first "25.7.30.2Class template slide_­view[range.slide.view]") = // *exposition only*![*slide-caches-nothing*](#concept:slide-caches-nothing "25.7.30.2Class template slide_­view[range.slide.view]")<V> && ![*slide-caches-last*](#concept:slide-caches-last "25.7.30.2Class template slide_­view[range.slide.view]")<V>; template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") V>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V>class slide_view : public view_interface<slide_view<V>> { V *base_*; // *exposition only* range_difference_t<V> *n_*; // *exposition only*// [[range.slide.iterator]](#range.slide.iterator "25.7.30.3Class template slide_­view::iterator"), class template slide_view::*iterator*template<bool> class *iterator*; // *exposition only*// [[range.slide.sentinel]](#range.slide.sentinel "25.7.30.4Class slide_­view::sentinel"), class slide_view::*sentinel*class *sentinel*; // *exposition only*public:constexpr explicit slide_view(V base, range_difference_t<V> n); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }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>)); constexpr auto begin() const requires [*slide-caches-nothing*](#concept:slide-caches-nothing "25.7.30.2Class template slide_­view[range.slide.view]")<const V>; 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>)); constexpr auto end() const requires [*slide-caches-nothing*](#concept:slide-caches-nothing "25.7.30.2Class template slide_­view[range.slide.view]")<const V>; 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>; constexpr auto reserve_hintsize() requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<V>; constexpr auto reserve_hintsize() const requires [approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<const V>; }; template<class R> slide_view(R&&, range_difference_t<R>) -> slide_view<views::all_t<R>>;}
[🔗](#lib:slide_view,constructor_)
`constexpr explicit slide_view(V base, range_difference_t<V> n);
`
[1](#range.slide.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14960)
*Preconditions*: n > 0 is true[.](#range.slide.view-1.sentence-1)
[2](#range.slide.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14964)
*Effects*: Initializes *base_* with std::move(base) and*n_* with n[.](#range.slide.view-2.sentence-1)
[🔗](#lib:begin,slide_view)
`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](#range.slide.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14977)
*Returns*:
- [(3.1)](#range.slide.view-3.1)
If V models [*slide-caches-first*](#concept:slide-caches-first "25.7.30.2Class template slide_­view[range.slide.view]"),*iterator*<false>(ranges::begin(*base_*),
ranges::next(ranges::begin(*base_*), *n_* - 1, ranges::end(*base_*)), *n_*)
- [(3.2)](#range.slide.view-3.2)
Otherwise, *iterator*<false>(ranges::begin(*base_*), *n_*)[.](#range.slide.view-3.sentence-1)
[4](#range.slide.view-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L14990)
*Remarks*: In order to provide the amortized constant-time complexity
required by the [range](range.range#concept:range "25.4.2Ranges[range.range]") concept,
this function caches the result within the slide_view for use on subsequent calls
when V models [*slide-caches-first*](#concept:slide-caches-first "25.7.30.2Class template slide_­view[range.slide.view]")[.](#range.slide.view-4.sentence-1)
[🔗](#lib:begin,slide_view_)
`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](#range.slide.view-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15005)
*Returns*: *iterator*<true>(ranges::begin(*base_*), *n_*)[.](#range.slide.view-5.sentence-1)
[🔗](#lib:end,slide_view)
`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](#range.slide.view-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15017)
*Returns*:
- [(6.1)](#range.slide.view-6.1)
If V models [*slide-caches-nothing*](#concept:slide-caches-nothing "25.7.30.2Class template slide_­view[range.slide.view]"),*iterator*<false>(ranges::begin(*base_*) + range_difference_t<V>(size()), *n_*)
- [(6.2)](#range.slide.view-6.2)
Otherwise, if V models [*slide-caches-last*](#concept:slide-caches-last "25.7.30.2Class template slide_­view[range.slide.view]"),*iterator*<false>(ranges::prev(ranges::end(*base_*), *n_* - 1, ranges::begin(*base_*)), *n_*)
- [(6.3)](#range.slide.view-6.3)
Otherwise, if V models [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]"),*iterator*<false>(ranges::end(*base_*), ranges::end(*base_*), *n_*)
- [(6.4)](#range.slide.view-6.4)
Otherwise, *sentinel*(ranges::end(*base_*))[.](#range.slide.view-6.sentence-1)
[7](#range.slide.view-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15039)
*Remarks*: In order to provide the amortized constant-time complexity
required by the [range](range.range#concept:range "25.4.2Ranges[range.range]") concept,
this function caches the result within the slide_view for use on subsequent calls
when V models [*slide-caches-last*](#concept:slide-caches-last "25.7.30.2Class template slide_­view[range.slide.view]")[.](#range.slide.view-7.sentence-1)
[🔗](#lib:end,slide_view_)
`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](#range.slide.view-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15054)
*Returns*: begin() + range_difference_t<const V>(size())[.](#range.slide.view-8.sentence-1)
[🔗](#lib:size,slide_view)
`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](#range.slide.view-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15066)
*Effects*: Equivalent to:auto sz = ranges::distance(*base_*) - *n_* + 1;if (sz < 0) sz = 0;return *to-unsigned-like*(sz);
[🔗](#lib:reserve_hint,slide_view)
`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](#range.slide.view-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15083)
*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](#range.slide.iterator) Class template slide_view::*iterator* [[range.slide.iterator]](range.slide.iterator)
[🔗](#lib:slide_view::iterator)
namespace std::ranges {template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") V>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V>template<bool Const>class slide_view<V>::*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*](#concept:slide-caches-first "25.7.30.2Class template slide_­view[range.slide.view]") range_difference_t<*Base*> *n_* = 0; // *exposition only*constexpr *iterator*(iterator_t<*Base*> current, range_difference_t<*Base*> n) // *exposition only*requires (![*slide-caches-first*](#concept:slide-caches-first "25.7.30.2Class template slide_­view[range.slide.view]")<*Base*>); constexpr *iterator*(iterator_t<*Base*> current, iterator_t<*Base*> last_ele, // *exposition only* range_difference_t<*Base*> n)requires [*slide-caches-first*](#concept:slide-caches-first "25.7.30.2Class template slide_­view[range.slide.view]")<*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*<!Const> i)requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<V>, iterator_t<*Base*>>; constexpr auto operator*() const; constexpr *iterator*& operator++(); constexpr *iterator* operator++(int); constexpr *iterator*& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator* operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator+=(difference_type x)requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator-=(difference_type x)requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr auto operator[](difference_type n) constrequires [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); 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]")<iterator_t<*Base*>>; 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*>; 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 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*>>; };}
[1](#range.slide.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15167)
*iterator*::iterator_concept is defined as follows:
- [(1.1)](#range.slide.iterator-1.1)
If *Base* models [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes random_access_iterator_tag[.](#range.slide.iterator-1.1.sentence-1)
- [(1.2)](#range.slide.iterator-1.2)
Otherwise, if *Base* models [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes bidirectional_iterator_tag[.](#range.slide.iterator-1.2.sentence-1)
- [(1.3)](#range.slide.iterator-1.3)
Otherwise, iterator_concept denotes forward_iterator_tag[.](#range.slide.iterator-1.3.sentence-1)
[2](#range.slide.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15180)
If the invocation of any non-const member function of *iterator* exits via an exception, the *iterator* acquires a singular value[.](#range.slide.iterator-2.sentence-1)
[🔗](#lib:slide_view::iterator,constructor)
`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](#range.slide.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15191)
*Effects*: Initializes *current_* with current and*n_* with n[.](#range.slide.iterator-3.sentence-1)
[🔗](#lib:slide_view::iterator,constructor_)
`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](#range.slide.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15205)
*Effects*: Initializes *current_* with current,*last_ele_* with last_ele, and*n_* with n[.](#range.slide.iterator-4.sentence-1)
[🔗](#lib:slide_view::iterator,constructor__)
`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](#range.slide.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15219)
*Effects*: Initializes *current_* with std::move(i.*current_*) and*n_* with i.*n_*[.](#range.slide.iterator-5.sentence-1)
[*Note [1](#range.slide.iterator-note-1)*:
*iterator*<true> can only be formed
when *Base* models [*slide-caches-nothing*](#concept:slide-caches-nothing "25.7.30.2Class template slide_­view[range.slide.view]"),
in which case *last_ele_* is not present[.](#range.slide.iterator-5.sentence-2)
— *end note*]
[🔗](#lib:operator*,slide_view::iterator)
`constexpr auto operator*() const;
`
[6](#range.slide.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15236)
*Returns*: views::counted(*current_*, *n_*)[.](#range.slide.iterator-6.sentence-1)
[🔗](#lib:operator++,slide_view::iterator)
`constexpr iterator& operator++();
`
[7](#range.slide.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15247)
*Preconditions*: *current_* and *last_ele_* (if present) are incrementable[.](#range.slide.iterator-7.sentence-1)
[8](#range.slide.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15251)
*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[.](#range.slide.iterator-8.sentence-1)
[9](#range.slide.iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15257)
*Returns*: *this[.](#range.slide.iterator-9.sentence-1)
[🔗](#lib:operator++,slide_view::iterator_)
`constexpr iterator operator++(int);
`
[10](#range.slide.iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15268)
*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,slide_view::iterator)
`constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[11](#range.slide.iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15284)
*Preconditions*: *current_* and *last_ele_* (if present) are decrementable[.](#range.slide.iterator-11.sentence-1)
[12](#range.slide.iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15288)
*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[.](#range.slide.iterator-12.sentence-1)
[13](#range.slide.iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15294)
*Returns*: *this[.](#range.slide.iterator-13.sentence-1)
[🔗](#lib:operator--,slide_view::iterator_)
`constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[14](#range.slide.iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15305)
*Effects*: Equivalent to:auto tmp = *this;--*this;return tmp;
[🔗](#lib:operator+=,slide_view::iterator)
`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](#range.slide.iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15322)
*Preconditions*: *current_* + x and *last_ele_* + x (if *last_ele_* is present)
have well-defined behavior[.](#range.slide.iterator-15.sentence-1)
[16](#range.slide.iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15327)
*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[.](#range.slide.iterator-16.sentence-1)
[17](#range.slide.iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15333)
*Returns*: *this[.](#range.slide.iterator-17.sentence-1)
[🔗](#lib:operator-=,slide_view::iterator)
`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](#range.slide.iterator-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15345)
*Preconditions*: *current_* - x and *last_ele_* - x (if *last_ele_* is present)
have well-defined behavior[.](#range.slide.iterator-18.sentence-1)
[19](#range.slide.iterator-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15350)
*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[.](#range.slide.iterator-19.sentence-1)
[20](#range.slide.iterator-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15356)
*Returns*: *this[.](#range.slide.iterator-20.sentence-1)
[🔗](#lib:operator%5b%5d,slide_view::iterator)
`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](#range.slide.iterator-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15368)
*Effects*: Equivalent to: return views::counted(*current_* + n, *n_*);
[🔗](#lib:operator==,slide_view::iterator)
`friend constexpr bool operator==(const iterator& x, const iterator& y);
`
[22](#range.slide.iterator-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15379)
*Returns*: If *last_ele_* is present,x.*last_ele_* == y.*last_ele_*;
otherwise, x.*current_* == y.*current_*[.](#range.slide.iterator-22.sentence-1)
[🔗](#lib:operator%3c,slide_view::iterator)
`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](#range.slide.iterator-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15393)
*Returns*: x.*current_* < y.*current_*[.](#range.slide.iterator-23.sentence-1)
[🔗](#lib:operator%3e,slide_view::iterator)
`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](#range.slide.iterator-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15405)
*Effects*: Equivalent to: return y < x;
[🔗](#lib:operator%3c=,slide_view::iterator)
`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](#range.slide.iterator-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15417)
*Effects*: Equivalent to: return !(y < x);
[🔗](#lib:operator%3e=,slide_view::iterator)
`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](#range.slide.iterator-26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15429)
*Effects*: Equivalent to: return !(x < y);
[🔗](#lib:operator%3c=%3e,slide_view::iterator)
`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](#range.slide.iterator-27)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15442)
*Returns*: x.*current_* <=> y.*current_*[.](#range.slide.iterator-27.sentence-1)
[🔗](#lib:operator+,slide_view::iterator)
`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](#range.slide.iterator-28)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15456)
*Effects*: Equivalent to:auto r = i;
r += n;return r;
[🔗](#lib:operator-,slide_view::iterator)
`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](#range.slide.iterator-29)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15473)
*Effects*: Equivalent to:auto r = i;
r -= n;return r;
[🔗](#lib:operator-,slide_view::iterator_)
`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](#range.slide.iterator-30)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15490)
*Returns*: If *last_ele_* is present,x.*last_ele_* - y.*last_ele_*;
otherwise, x.*current_* - y.*current_*[.](#range.slide.iterator-30.sentence-1)
#### [25.7.30.4](#range.slide.sentinel) Class slide_view::*sentinel* [[range.slide.sentinel]](range.slide.sentinel)
[🔗](#lib:slide_view::sentinel)
namespace std::ranges {template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") V>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V>class slide_view<V>::*sentinel* { sentinel_t<V> *end_* = sentinel_t<V>(); // *exposition only*constexpr explicit *sentinel*(sentinel_t<V> end); // *exposition only*public:*sentinel*() = default; friend constexpr bool operator==(const *iterator*<false>& x, const *sentinel*& y); 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>>; 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>>; };}
[1](#range.slide.sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15524)
[*Note [1](#range.slide.sentinel-note-1)*:
*sentinel* is used
only when [*slide-caches-first*](#concept:slide-caches-first "25.7.30.2Class template slide_­view[range.slide.view]")<V> is true[.](#range.slide.sentinel-1.sentence-1)
— *end note*]
[🔗](#lib:slide_view::sentinel,constructor)
`constexpr explicit sentinel(sentinel_t<V> end);
`
[2](#range.slide.sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15536)
*Effects*: Initializes *end_* with end[.](#range.slide.sentinel-2.sentence-1)
[🔗](#lib:operator==,slide_view::sentinel)
`friend constexpr bool operator==(const iterator<false>& x, const sentinel& y);
`
[3](#range.slide.sentinel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15547)
*Returns*: x.*last_ele_* == y.*end_*[.](#range.slide.sentinel-3.sentence-1)
[🔗](#lib:operator-,slide_view::sentinel)
`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](#range.slide.sentinel-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15560)
*Returns*: x.*last_ele_* - y.*end_*[.](#range.slide.sentinel-4.sentence-1)
[🔗](#lib:operator-,slide_view::sentinel_)
`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](#range.slide.sentinel-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15573)
*Returns*: y.*end_* - x.*last_ele_*[.](#range.slide.sentinel-5.sentence-1)
### [25.7.31](#range.chunk.by) Chunk by view [[range.chunk.by]](range.chunk.by)
#### [25.7.31.1](#range.chunk.by.overview) Overview [[range.chunk.by.overview]](range.chunk.by.overview)
[1](#range.chunk.by.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15582)
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[.](#range.chunk.by.overview-1.sentence-1)
[2](#range.chunk.by.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15588)
The name views::chunk_by denotes
a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.chunk.by.overview-2.sentence-1)
Given subexpressions E and F,
the expression views::chunk_by(E, F) is expression-equivalent tochunk_by_view(E, F)[.](#range.chunk.by.overview-2.sentence-2)
[*Example [1](#range.chunk.by.overview-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](#range.chunk.by.view) Class template chunk_by_view [[range.chunk.by.view]](range.chunk.by.view)
[🔗](#lib:chunk_by_view)
namespace std::ranges {template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") V, [indirect_binary_predicate](indirectcallable.indirectinvocable#concept:indirect_binary_predicate "24.3.6.3Indirect callables[indirectcallable.indirectinvocable]")<iterator_t<V>, iterator_t<V>> Pred>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && is_object_v<Pred>class chunk_by_view : public view_interface<chunk_by_view<V, Pred>> { V *base_* = V(); // *exposition only**movable-box*<Pred> *pred_*; // *exposition only*// [[range.chunk.by.iter]](#range.chunk.by.iter "25.7.31.3Class chunk_­by_­view::iterator"), class chunk_by_view::*iterator*class *iterator*; // *exposition only*public: chunk_by_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> && [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<Pred> = default; constexpr explicit chunk_by_view(V base, Pred pred); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr const Pred& pred() const; constexpr *iterator* begin(); constexpr auto end(); constexpr iterator_t<V> *find-next*(iterator_t<V>); // *exposition only*constexpr iterator_t<V> *find-prev*(iterator_t<V>) // *exposition only*requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<V>; }; template<class R, class Pred> chunk_by_view(R&&, Pred) -> chunk_by_view<views::all_t<R>, Pred>;}
[🔗](#lib:chunk_by_view,constructor)
`constexpr explicit chunk_by_view(V base, Pred pred);
`
[1](#range.chunk.by.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15654)
*Effects*: Initializes *base_* with std::move(base) and*pred_* with std::move(pred)[.](#range.chunk.by.view-1.sentence-1)
[🔗](#lib:pred,chunk_by_view)
`constexpr const Pred& pred() const;
`
[2](#range.chunk.by.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15666)
*Effects*: Equivalent to: return **pred_*;
[🔗](#lib:begin,chunk_by_view)
`constexpr iterator begin();
`
[3](#range.chunk.by.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15677)
*Preconditions*: *pred_*.has_value() is true[.](#range.chunk.by.view-3.sentence-1)
[4](#range.chunk.by.view-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15681)
*Returns*: *iterator*(*this, ranges::begin(*base_*), *find-next*(ranges::begin(*base_*)))[.](#range.chunk.by.view-4.sentence-1)
[5](#range.chunk.by.view-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15685)
*Remarks*: In order to provide
the amortized constant-time complexity required by the [range](range.range#concept:range "25.4.2Ranges[range.range]") concept,
this function caches the result within the chunk_by_view for use on subsequent calls[.](#range.chunk.by.view-5.sentence-1)
[🔗](#lib:end,chunk_by_view)
`constexpr auto end();
`
[6](#range.chunk.by.view-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15699)
*Effects*: Equivalent to:if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V>) {return *iterator*(*this, ranges::end(*base_*), ranges::end(*base_*));} else {return default_sentinel;}
[🔗](#lib:find-next,chunk_by_view)
`constexpr iterator_t<V> find-next(iterator_t<V> current);
`
[7](#range.chunk.by.view-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15717)
*Preconditions*: *pred_*.has_value() is true[.](#range.chunk.by.view-7.sentence-1)
[8](#range.chunk.by.view-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15721)
*Returns*: ranges::next(ranges::adjacent_find(current, ranges::end(*base_*), not_fn(ref(**pred_*))), 1, ranges::end(*base_*))
[🔗](#lib:find-prev,chunk_by_view)
`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](#range.chunk.by.view-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15735)
*Preconditions*:
- [(9.1)](#range.chunk.by.view-9.1)
current is not equal to ranges::begin(*base_*)[.](#range.chunk.by.view-9.1.sentence-1)
- [(9.2)](#range.chunk.by.view-9.2)
*pred_*.has_value() is true[.](#range.chunk.by.view-9.2.sentence-1)
[10](#range.chunk.by.view-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15744)
*Returns*: An iterator i in the range [ranges::begin(*base_*), current) such that:
- [(10.1)](#range.chunk.by.view-10.1)
ranges::adjacent_find(i, current, not_fn(ref(**pred_*))) is equal to current; and
- [(10.2)](#range.chunk.by.view-10.2)
if i is not equal to ranges::begin(*base_*),
then bool(invoke(**pred_*, *ranges::prev(i), *i)) is false[.](#range.chunk.by.view-10.sentence-1)
#### [25.7.31.3](#range.chunk.by.iter) Class chunk_by_view::*iterator* [[range.chunk.by.iter]](range.chunk.by.iter)
[🔗](#lib:chunk_by_view::iterator)
namespace std::ranges {template<[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") V, [indirect_binary_predicate](indirectcallable.indirectinvocable#concept:indirect_binary_predicate "24.3.6.3Indirect callables[indirectcallable.indirectinvocable]")<iterator_t<V>, iterator_t<V>> Pred>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && is_object_v<Pred>class chunk_by_view<V, Pred>::*iterator* { chunk_by_view* *parent_* = nullptr; // *exposition only* iterator_t<V> *current_* = iterator_t<V>(); // *exposition only* iterator_t<V> *next_* = iterator_t<V>(); // *exposition only*constexpr *iterator*(chunk_by_view& parent, iterator_t<V> current, // *exposition only* iterator_t<V> next); public:using value_type = subrange<iterator_t<V>>; using difference_type = range_difference_t<V>; 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](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<V>; constexpr *iterator* operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<V>; friend constexpr bool operator==(const *iterator*& x, const *iterator*& y); friend constexpr bool operator==(const *iterator*& x, default_sentinel_t); };}
[1](#range.chunk.by.iter-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15794)
*iterator*::iterator_concept is defined as follows:
- [(1.1)](#range.chunk.by.iter-1.1)
If V models [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes bidirectional_iterator_tag[.](#range.chunk.by.iter-1.1.sentence-1)
- [(1.2)](#range.chunk.by.iter-1.2)
Otherwise, iterator_concept denotes forward_iterator_tag[.](#range.chunk.by.iter-1.2.sentence-1)
[🔗](#lib:chunk_by_view::iterator,constructor)
`constexpr iterator(chunk_by_view& parent, iterator_t<V> current, iterator_t<V> next);
`
[2](#range.chunk.by.iter-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15810)
*Effects*: Initializes *parent_* with addressof(parent),*current_* with current, and*next_* with next[.](#range.chunk.by.iter-2.sentence-1)
[🔗](#lib:operator*,chunk_by_view::iterator)
`constexpr value_type operator*() const;
`
[3](#range.chunk.by.iter-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15823)
*Preconditions*: *current_* is not equal to *next_*[.](#range.chunk.by.iter-3.sentence-1)
[4](#range.chunk.by.iter-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15827)
*Returns*: subrange(*current_*, *next_*)[.](#range.chunk.by.iter-4.sentence-1)
[🔗](#lib:operator++,chunk_by_view::iterator)
`constexpr iterator& operator++();
`
[5](#range.chunk.by.iter-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15838)
*Preconditions*: *current_* is not equal to *next_*[.](#range.chunk.by.iter-5.sentence-1)
[6](#range.chunk.by.iter-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15842)
*Effects*: Equivalent to:*current_* = *next_*;*next_* = *parent_*->*find-next*(*current_*);return *this;
[🔗](#lib:operator++,chunk_by_view::iterator_)
`constexpr iterator operator++(int);
`
[7](#range.chunk.by.iter-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15858)
*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,chunk_by_view::iterator)
`constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<V>;
`
[8](#range.chunk.by.iter-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15874)
*Effects*: Equivalent to:*next_* = *current_*;*current_* = *parent_*->*find-prev*(*next_*);return *this;
[🔗](#lib:operator--,chunk_by_view::iterator_)
`constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<V>;
`
[9](#range.chunk.by.iter-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15890)
*Effects*: Equivalent to:auto tmp = *this;--*this;return tmp;
[🔗](#lib:operator==,chunk_by_view::iterator)
`friend constexpr bool operator==(const iterator& x, const iterator& y);
`
[10](#range.chunk.by.iter-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15906)
*Returns*: x.*current_* == y.*current_*[.](#range.chunk.by.iter-10.sentence-1)
[🔗](#lib:operator==,chunk_by_view::iterator_)
`friend constexpr bool operator==(const iterator& x, default_sentinel_t);
`
[11](#range.chunk.by.iter-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15917)
*Returns*: x.*current_* == x.*next_*[.](#range.chunk.by.iter-11.sentence-1)
### [25.7.32](#range.stride) Stride view [[range.stride]](range.stride)
#### [25.7.32.1](#range.stride.overview) Overview [[range.stride.overview]](range.stride.overview)
[1](#range.stride.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15926)
stride_view presents a view of an underlying sequence,
advancing over n elements at a time,
as opposed to the usual single-step succession[.](#range.stride.overview-1.sentence-1)
[2](#range.stride.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15931)
The name views::stride denotes
a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.stride.overview-2.sentence-1)
Given subexpressions E and N,
the expression views::stride(E, N) is expression-equivalent to stride_view(E, N)[.](#range.stride.overview-2.sentence-2)
[3](#range.stride.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L15938)
[*Example [1](#range.stride.overview-example-1)*: auto input = views::iota(0, 12) | views::stride(3);
ranges::copy(input, ostream_iterator<int>(cout, " ")); // prints 0 3 6 9 ranges::copy(input | views::reverse, ostream_iterator<int>(cout, " ")); // prints 9 6 3 0 — *end example*]
#### [25.7.32.2](#range.stride.view) Class template stride_view [[range.stride.view]](range.stride.view)
[🔗](#lib:stride_view)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V>class stride_view : public view_interface<stride_view<V>> { V *base_*; // *exposition only* range_difference_t<V> *stride_*; // *exposition only*// [[range.stride.iterator]](#range.stride.iterator "25.7.32.3Class template stride_­view::iterator"), class template stride_view::*iterator*template<bool> class *iterator*; // *exposition only*public:constexpr explicit stride_view(V base, range_difference_t<V> stride); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr range_difference_t<V> stride() const noexcept; constexpr auto begin() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>) {return *iterator*<false>(this, ranges::begin(*base_*)); }constexpr auto begin() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V> {return *iterator*<true>(this, ranges::begin(*base_*)); }constexpr auto end() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>) {if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V> && [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<V> && [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>) {auto missing = (*stride_* - ranges::distance(*base_*) % *stride_*) % *stride_*; return *iterator*<false>(this, ranges::end(*base_*), missing); } else if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V> && ![bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<V>) {return *iterator*<false>(this, ranges::end(*base_*)); } else {return default_sentinel; }}constexpr auto end() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V> {if constexpr ([common_range](range.refinements#concept:common_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> && [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const V>) {auto missing = (*stride_* - ranges::distance(*base_*) % *stride_*) % *stride_*; return *iterator*<true>(this, ranges::end(*base_*), missing); } else if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<const V> && ![bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<const V>) {return *iterator*<true>(this, ranges::end(*base_*)); } else {return 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>; 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>; }; template<class R> stride_view(R&&, range_difference_t<R>) -> stride_view<views::all_t<R>>;}
[🔗](#lib:stride_view,constructor)
`constexpr stride_view(V base, range_difference_t<V> stride);
`
[1](#range.stride.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16015)
*Preconditions*: stride > 0 is true[.](#range.stride.view-1.sentence-1)
[2](#range.stride.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16019)
*Effects*: Initializes *base_* with std::move(base) and*stride_* with stride[.](#range.stride.view-2.sentence-1)
[🔗](#lib:stride,stride_view)
`constexpr range_difference_t<V> stride() const noexcept;
`
[3](#range.stride.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16031)
*Returns*: *stride_*[.](#range.stride.view-3.sentence-1)
[🔗](#lib:size,stride_view)
`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](#range.stride.view-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16043)
*Effects*: Equivalent to:return *to-unsigned-like*(*div-ceil*(ranges::distance(*base_*), *stride_*));
[🔗](#lib:reserve_hint,stride_view)
`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](#range.stride.view-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16058)
*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](#range.stride.iterator) Class template stride_view::*iterator* [[range.stride.iterator]](range.stride.iterator)
[🔗](#lib:stride_view::iterator)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V>template<bool Const>class stride_view<V>::*iterator* {using *Parent* = *maybe-const*<Const, stride_view>; // *exposition only*using *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 only*constexpr *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 present*iterator*() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<iterator_t<*Base*>> = default; constexpr *iterator*(*iterator*<!Const> other)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*>>; 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](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator* operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator+=(difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr *iterator*& operator-=(difference_type n) requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; constexpr decltype(auto) operator[](difference_type n) constrequires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*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](concept.equalitycomparable#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<iterator_t<*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 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]")<iterator_t<*Base*>>; friend constexpr *iterator* operator+(const *iterator*& x, 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*& x)requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; friend constexpr *iterator* operator-(const *iterator*& x, difference_type n)requires [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*Base*>; 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*>>; 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*>>; 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*>>; 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](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<*Base*>>; };}
[1](#range.stride.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16161)
*iterator*::iterator_concept is defined as follows:
- [(1.1)](#range.stride.iterator-1.1)
If *Base* models [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes random_access_iterator_tag[.](#range.stride.iterator-1.1.sentence-1)
- [(1.2)](#range.stride.iterator-1.2)
Otherwise, if *Base* models [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes bidirectional_iterator_tag[.](#range.stride.iterator-1.2.sentence-1)
- [(1.3)](#range.stride.iterator-1.3)
Otherwise, if *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes forward_iterator_tag[.](#range.stride.iterator-1.3.sentence-1)
- [(1.4)](#range.stride.iterator-1.4)
Otherwise, iterator_concept denotes input_iterator_tag[.](#range.stride.iterator-1.4.sentence-1)
[2](#range.stride.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16177)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") iterator_category is defined
if and only if *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")[.](#range.stride.iterator-2.sentence-1)
In that case,*iterator*::iterator_category is defined as follows:
- [(2.1)](#range.stride.iterator-2.1)
Let C denote
the type iterator_traits<iterator_t<*Base*>>::iterator_category[.](#range.stride.iterator-2.1.sentence-1)
- [(2.2)](#range.stride.iterator-2.2)
If C models[derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<random_access_iterator_tag>,
then iterator_category denotes random_access_iterator_tag[.](#range.stride.iterator-2.2.sentence-1)
- [(2.3)](#range.stride.iterator-2.3)
Otherwise, iterator_category denotes C[.](#range.stride.iterator-2.3.sentence-1)
[🔗](#lib:stride_view::iterator,constructor)
`constexpr iterator(Parent* parent, iterator_t<Base> current,
range_difference_t<Base> missing = 0);
`
[3](#range.stride.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16201)
*Effects*: Initializes *current_* with std::move(current),*end_* with ranges::end(parent->*base_*),*stride_* with parent->*stride_*, and*missing_* with missing[.](#range.stride.iterator-3.sentence-1)
[🔗](#lib:stride_view::iterator,constructor_)
`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](#range.stride.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16217)
*Effects*: Initializes *current_* with std::move(i.*current_*),*end_* with std::move(i.*end_*),*stride_* with i.*stride_*, and*missing_* with i.*missing_*[.](#range.stride.iterator-4.sentence-1)
[🔗](#lib:base,stride_view::iterator)
`constexpr iterator_t<Base> base() &&;
`
[5](#range.stride.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16231)
*Returns*: std::move(*current_*)[.](#range.stride.iterator-5.sentence-1)
[🔗](#lib:base,stride_view::iterator_)
`constexpr const iterator_t<Base>& base() const & noexcept;
`
[6](#range.stride.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16242)
*Returns*: *current_*[.](#range.stride.iterator-6.sentence-1)
[🔗](#lib:operator++,stride_view::iterator)
`constexpr iterator& operator++();
`
[7](#range.stride.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16253)
*Preconditions*: *current_* != *end_* is true[.](#range.stride.iterator-7.sentence-1)
[8](#range.stride.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16257)
*Effects*: Equivalent to:*missing_* = ranges::advance(*current_*, *stride_*, *end_*);return *this;
[🔗](#lib:operator++,stride_view::iterator_)
`constexpr void operator++(int);
`
[9](#range.stride.iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16272)
*Effects*: Equivalent to ++*this;
[🔗](#lib:operator++,stride_view::iterator__)
`constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[10](#range.stride.iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16283)
*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,stride_view::iterator)
`constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[11](#range.stride.iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16299)
*Effects*: Equivalent to:ranges::advance(*current_*, *missing_* - *stride_*);*missing_* = 0;return *this;
[🔗](#lib:operator--,stride_view::iterator_)
`constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base>;
`
[12](#range.stride.iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16315)
*Effects*: Equivalent to:auto tmp = *this;--*this;return tmp;
[🔗](#lib:operator+=,stride_view::iterator)
`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](#range.stride.iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16331)
*Preconditions*: If n is positive,ranges::distance(*current_*, *end_*) > *stride_* * (n - 1) is true[.](#range.stride.iterator-13.sentence-1)
[*Note [1](#range.stride.iterator-note-1)*:
If n is negative, the *Effects* paragraph implies a precondition[.](#range.stride.iterator-13.sentence-2)
— *end note*]
[14](#range.stride.iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16340)
*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;
[🔗](#lib:operator-=,stride_view::iterator)
`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](#range.stride.iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16362)
*Effects*: Equivalent to: return *this += -x;
[🔗](#lib:operator==,stride_view::iterator)
`friend constexpr bool operator==(const iterator& x, default_sentinel_t);
`
[16](#range.stride.iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16373)
*Returns*: x.*current_* == x.*end_*[.](#range.stride.iterator-16.sentence-1)
[🔗](#lib:operator==,stride_view::iterator_)
`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](#range.stride.iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16385)
*Returns*: x.*current_* == y.*current_*[.](#range.stride.iterator-17.sentence-1)
[🔗](#lib:operator%3c,stride_view::iterator)
`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](#range.stride.iterator-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16397)
*Returns*: x.*current_* < y.*current_*[.](#range.stride.iterator-18.sentence-1)
[🔗](#lib:operator%3e,stride_view::iterator)
`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](#range.stride.iterator-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16409)
*Effects*: Equivalent to: return y < x;
[🔗](#lib:operator%3c=,stride_view::iterator)
`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](#range.stride.iterator-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16421)
*Effects*: Equivalent to: return !(y < x);
[🔗](#lib:operator%3e=,stride_view::iterator)
`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](#range.stride.iterator-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16433)
*Effects*: Equivalent to: return !(x < y);
[🔗](#lib:operator%3c=%3e,stride_view::iterator)
`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](#range.stride.iterator-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16445)
*Returns*: x.*current_* <=> y.*current_*[.](#range.stride.iterator-22.sentence-1)
[🔗](#lib:operator+,stride_view::iterator)
`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](#range.stride.iterator-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16459)
*Effects*: Equivalent to:auto r = i;
r += n;return r;
[🔗](#lib:operator-,stride_view::iterator)
`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](#range.stride.iterator-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16476)
*Effects*: Equivalent to:auto r = i;
r -= n;return r;
[🔗](#lib:operator-,stride_view::iterator_)
`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](#range.stride.iterator-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16493)
*Returns*: Let N be (x.*current_* - y.*current_*)[.](#range.stride.iterator-25.sentence-1)
- [(25.1)](#range.stride.iterator-25.1)
If *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"),(N + x.*missing_* - y.*missing_*) / x.*stride_*[.](#range.stride.iterator-25.1.sentence-1)
- [(25.2)](#range.stride.iterator-25.2)
Otherwise, if N is negative, -*div-ceil*(-N, x.*stride_*)[.](#range.stride.iterator-25.2.sentence-1)
- [(25.3)](#range.stride.iterator-25.3)
Otherwise, *div-ceil*(N, x.*stride_*)[.](#range.stride.iterator-25.3.sentence-1)
[🔗](#lib:operator-,stride_view::iterator__)
`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](#range.stride.iterator-26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16514)
*Returns*: *div-ceil*(x.*end_* - x.*current_*, x.*stride_*)[.](#range.stride.iterator-26.sentence-1)
[🔗](#lib:operator-,stride_view::iterator___)
`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](#range.stride.iterator-27)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16526)
*Effects*: Equivalent to: return -(y - x);
[🔗](#lib:iter_move,stride_view::iterator)
`friend constexpr range_rvalue_reference_t<Base> iter_move(const iterator& i)
noexcept(noexcept(ranges::iter_move(i.current_)));
`
[28](#range.stride.iterator-28)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16538)
*Effects*: Equivalent to: return ranges::iter_move(i.*current_*);
[🔗](#lib:iter_swap,stride_view::iterator)
`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](#range.stride.iterator-29)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16551)
*Effects*: Equivalent to:ranges::iter_swap(x.*current_*, y.*current_*);
### [25.7.33](#range.cartesian) Cartesian product view [[range.cartesian]](range.cartesian)
#### [25.7.33.1](#range.cartesian.overview) Overview [[range.cartesian.overview]](range.cartesian.overview)
[1](#range.cartesian.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16562)
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[.](#range.cartesian.overview-1.sentence-1)
[2](#range.cartesian.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16567)
The name views::cartesian_product denotes a customization point object ([[customization.point.object]](customization.point.object "16.3.3.3.5Customization Point Object types"))[.](#range.cartesian.overview-2.sentence-1)
Given a pack of subexpressions Es,
the expression views::cartesian_product(Es...) is expression-equivalent to
- [(2.1)](#range.cartesian.overview-2.1)
views::single(tuple()) if Es is an empty pack,
- [(2.2)](#range.cartesian.overview-2.2)
otherwise,cartesian_product_view<views::all_t<decltype((Es))>...>(Es...)[.](#range.cartesian.overview-2.sentence-2)
[3](#range.cartesian.overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16581)
[*Example [1](#range.cartesian.overview-example-1)*: vector<int> 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](#range.cartesian.view) Class template cartesian_product_view [[range.cartesian.view]](range.cartesian.view)
[🔗](#lib:cartesian_product_view_)
namespace std::ranges {template<bool Const, class First, class... Vs>concept [*cartesian-product-is-random-access*](#concept:cartesian-product-is-random-access "25.7.33.2Class template cartesian_­product_­view[range.cartesian.view]") = // *exposition only*([random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*maybe-const*<Const, First>> && ... &&([random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<*maybe-const*<Const, Vs>>&& [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<*maybe-const*<Const, Vs>>)); template<class R>concept [*cartesian-product-common-arg*](#concept:cartesian-product-common-arg "25.7.33.2Class template cartesian_­product_­view[range.cartesian.view]") = // *exposition only*[common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<R> || ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<R> && [random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]")<R>); template<bool Const, class First, class... Vs>concept [*cartesian-product-is-bidirectional*](#concept:cartesian-product-is-bidirectional "25.7.33.2Class template cartesian_­product_­view[range.cartesian.view]") = // *exposition only*([bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*maybe-const*<Const, First>> && ... &&([bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*maybe-const*<Const, Vs>>&& [*cartesian-product-common-arg*](#concept:cartesian-product-common-arg "25.7.33.2Class template cartesian_­product_­view[range.cartesian.view]")<*maybe-const*<Const, Vs>>)); template<class First, class...>concept [*cartesian-product-is-common*](#concept:cartesian-product-is-common "25.7.33.2Class template cartesian_­product_­view[range.cartesian.view]") = // *exposition only*[*cartesian-product-common-arg*](#concept:cartesian-product-common-arg "25.7.33.2Class template cartesian_­product_­view[range.cartesian.view]")<First>; template<class... Vs>concept [*cartesian-product-is-sized*](#concept:cartesian-product-is-sized "25.7.33.2Class template cartesian_­product_­view[range.cartesian.view]") = // *exposition only*([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<Vs> && ...); template<bool Const, template<class> class FirstSent, class First, class... Vs>concept [*cartesian-is-sized-sentinel*](#concept:cartesian-is-sized-sentinel "25.7.33.2Class template cartesian_­product_­view[range.cartesian.view]") = // *exposition only*([sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<FirstSent<*maybe-const*<Const, First>>,
iterator_t<*maybe-const*<Const, First>>> && ...&& ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<*maybe-const*<Const, Vs>>&& [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, Vs>>,
iterator_t<*maybe-const*<Const, Vs>>>)); template<[*cartesian-product-common-arg*](#concept:cartesian-product-common-arg "25.7.33.2Class template cartesian_­product_­view[range.cartesian.view]") R>constexpr auto *cartesian-common-arg-end*(R& r) { // *exposition only*if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<R>) {return ranges::end(r); } else {return ranges::begin(r) + ranges::distance(r); }}template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") First, [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")... Vs>requires ([view](range.view#concept:view "25.4.5Views[range.view]")<First> && ... && [view](range.view#concept:view "25.4.5Views[range.view]")<Vs>)class cartesian_product_view : public view_interface<cartesian_product_view<First, Vs...>> {private: tuple<First, Vs...> *bases_*; // *exposition only*// [[range.cartesian.iterator]](#range.cartesian.iterator "25.7.33.3Class template cartesian_­product_­view::iterator"), class template cartesian_product_view::*iterator*template<bool Const> class *iterator*; // *exposition only*public:constexpr cartesian_product_view() = default; constexpr explicit cartesian_product_view(First first_base, Vs... 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>); constexpr *iterator*<true> begin() constrequires ([range](range.range#concept:range "25.4.2Ranges[range.range]")<const First> && ... && [range](range.range#concept:range "25.4.2Ranges[range.range]")<const Vs>); 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() constrequires [*cartesian-product-is-common*](#concept:cartesian-product-is-common "25.7.33.2Class template cartesian_­product_­view[range.cartesian.view]")<const First, const Vs...>; constexpr default_sentinel_t end() const noexcept; 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() constrequires [*cartesian-product-is-sized*](#concept:cartesian-product-is-sized "25.7.33.2Class template cartesian_­product_­view[range.cartesian.view]")<const First, const Vs...>; }; template<class... Vs> cartesian_product_view(Vs&&...) -> cartesian_product_view<views::all_t<Vs>...>;}
[🔗](#lib:cartesian_product_view,constructor)
`constexpr explicit cartesian_product_view(First first_base, Vs... bases);
`
[1](#range.cartesian.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16685)
*Effects*: Initializes *bases_* with std::move(first_base), std::move(bases)...[.](#range.cartesian.view-1.sentence-1)
[🔗](#lib:begin,cartesian_product_view)
`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](#range.cartesian.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16698)
*Effects*: Equivalent to:return *iterator*<false>(*this, *tuple-transform*(ranges::begin, *bases_*));
[🔗](#lib:begin,cartesian_product_view_)
`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](#range.cartesian.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16713)
*Effects*: Equivalent to:return *iterator*<true>(*this, *tuple-transform*(ranges::begin, *bases_*));
[🔗](#lib:end,cartesian_product_view)
`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](#range.cartesian.view-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16731)
Let:
- [(4.1)](#range.cartesian.view-4.1)
*is-const* be true for the const-qualified overload, andfalse otherwise;
- [(4.2)](#range.cartesian.view-4.2)
*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
- [(4.3)](#range.cartesian.view-4.3)
*begin-or-first-end*(rng) be expression-equivalent to*is-empty* ? ranges::begin(rng) : *cartesian-common-arg-end*(rng) if rng is the first underlying range andranges::begin(rng) otherwise[.](#range.cartesian.view-4.sentence-1)
[5](#range.cartesian.view-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16749)
*Effects*: Equivalent to:*iterator*<*is-const*> it(*this, *tuple-transform*([](auto& rng){ return *begin-or-first-end*(rng); }, *bases_*));return it;
[🔗](#lib:end,cartesian_product_view_)
`constexpr default_sentinel_t end() const noexcept;
`
[6](#range.cartesian.view-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16765)
*Returns*: default_sentinel[.](#range.cartesian.view-6.sentence-1)
[🔗](#lib:size,cartesian_product_view)
`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](#range.cartesian.view-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16779)
The return type is an implementation-defined unsigned-integer-like type[.](#range.cartesian.view-7.sentence-1)
[8](#range.cartesian.view-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16782)
*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[.](#range.cartesian.view-8.sentence-1)
[9](#range.cartesian.view-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16788)
Let p be the product of the sizes of all the ranges in *bases_*[.](#range.cartesian.view-9.sentence-1)
[10](#range.cartesian.view-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16791)
*Preconditions*: p can be represented by the return type[.](#range.cartesian.view-10.sentence-1)
[11](#range.cartesian.view-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16795)
*Returns*: p[.](#range.cartesian.view-11.sentence-1)
#### [25.7.33.3](#range.cartesian.iterator) Class template cartesian_product_view::*iterator* [[range.cartesian.iterator]](range.cartesian.iterator)
[🔗](#lib:cartesian_product_view::iterator)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") First, [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")... Vs>requires ([view](range.view#concept:view "25.4.5Views[range.view]")<First> && ... && [view](range.view#concept:view "25.4.5Views[range.view]")<Vs>)template<bool Const>class 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*<!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>>); constexpr auto operator*() const; constexpr *iterator*& operator++(); constexpr void operator++(int); constexpr *iterator* operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*maybe-const*<Const, First>>; 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...>; 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...>; 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...>; 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...>; constexpr reference operator[](difference_type n) constrequires [*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...>; 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>>>; friend constexpr bool operator==(const *iterator*& x, default_sentinel_t); 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...>; 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...>; 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...>; 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...>; 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...>; 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...>; friend constexpr difference_type operator-(default_sentinel_t, 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...>; 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](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>>>); private:using *Parent* = *maybe-const*<Const, cartesian_product_view>; // *exposition only**Parent** *parent_* = nullptr; // *exposition only* tuple<iterator_t<*maybe-const*<Const, First>>,
iterator_t<*maybe-const*<Const, Vs>>...> *current_*; // *exposition only*template<size_t N = sizeof...(Vs)>constexpr void *next*(); // *exposition only*template<size_t N = sizeof...(Vs)>constexpr void *prev*(); // *exposition only*template<class Tuple>constexpr difference_type *distance-from*(const Tuple& t) const; // *exposition only*constexpr *iterator*(*Parent*& parent, tuple<iterator_t<*maybe-const*<Const, First>>,
iterator_t<*maybe-const*<Const, Vs>>...> current); // *exposition only*};}
[1](#range.cartesian.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16891)
*iterator*::iterator_concept is defined as follows:
- [(1.1)](#range.cartesian.iterator-1.1)
If [*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...> is modeled,
then iterator_concept denotes random_access_iterator_tag[.](#range.cartesian.iterator-1.1.sentence-1)
- [(1.2)](#range.cartesian.iterator-1.2)
Otherwise,
if [*cartesian-product-is-bidirectional*](#concept:cartesian-product-is-bidirectional "25.7.33.2Class template cartesian_­product_­view[range.cartesian.view]")<Const, First, Vs...> is modeled,
then iterator_concept denotes bidirectional_iterator_tag[.](#range.cartesian.iterator-1.2.sentence-1)
- [(1.3)](#range.cartesian.iterator-1.3)
Otherwise,
if *maybe-const*<Const, First> models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes forward_iterator_tag[.](#range.cartesian.iterator-1.3.sentence-1)
- [(1.4)](#range.cartesian.iterator-1.4)
Otherwise, iterator_concept denotes input_iterator_tag[.](#range.cartesian.iterator-1.4.sentence-1)
[2](#range.cartesian.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16911)
*iterator*::difference_type is
an implementation-defined
signed-integer-like type[.](#range.cartesian.iterator-2.sentence-1)
[3](#range.cartesian.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16916)
*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[.](#range.cartesian.iterator-3.sentence-1)
[🔗](#lib:next,cartesian_product_view)
`template<size_t N = sizeof...(Vs)>
constexpr void next();
`
[4](#range.cartesian.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16931)
*Effects*: Equivalent to:auto& it = std::get<N>(*current_*);++it;if constexpr (N > 0) {if (it == ranges::end(std::get<N>(*parent_*->*bases_*))) { it = ranges::begin(std::get<N>(*parent_*->*bases_*)); *next*<N - 1>(); }}
[🔗](#lib:prev,cartesian_product_view)
`template<size_t N = sizeof...(Vs)>
constexpr void prev();
`
[5](#range.cartesian.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16953)
*Effects*: Equivalent to:auto& it = std::get<N>(*current_*);if constexpr (N > 0) {if (it == ranges::begin(std::get<N>(*parent_*->*bases_*))) { it = *cartesian-common-arg-end*(std::get<N>(*parent_*->*bases_*)); *prev*<N - 1>(); }}--it;
[🔗](#lib:distance-from,cartesian_product_view)
`template<class Tuple>
constexpr difference_type distance-from(const Tuple& t) const;
`
[6](#range.cartesian.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16975)
Let:
- [(6.1)](#range.cartesian.iterator-6.1)
*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);
- [(6.2)](#range.cartesian.iterator-6.2)
*scaled-distance*(N) be the product ofstatic_cast<difference_type>(std::get<N>(*current_*) - std::get<N>(t)) and scaled-size(N+1); and
- [(6.3)](#range.cartesian.iterator-6.3)
*scaled-sum* be the sum of *scaled-distance*(N) for every integer 0 ≤ N ≤ sizeof...(Vs)[.](#range.cartesian.iterator-6.sentence-1)
[7](#range.cartesian.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16991)
*Preconditions*: *scaled-sum* can be represented by difference_type[.](#range.cartesian.iterator-7.sentence-1)
[8](#range.cartesian.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16995)
*Returns*: *scaled-sum*[.](#range.cartesian.iterator-8.sentence-1)
[🔗](#lib:cartesian_product_view::iterator,constructor)
`constexpr iterator(Parent& parent, tuple<iterator_t<maybe-const<Const, First>>,
iterator_t<maybe-const<Const, Vs>>...> current);
`
[9](#range.cartesian.iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17007)
*Effects*: Initializes*parent_* with addressof(parent) and*current_* with std::move(current)[.](#range.cartesian.iterator-9.sentence-1)
[🔗](#lib:cartesian_product_view::iterator,constructor_)
`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](#range.cartesian.iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17022)
*Effects*: Initializes*parent_* with i.*parent_* and*current_* with std::move(i.*current_*)[.](#range.cartesian.iterator-10.sentence-1)
[🔗](#lib:operator*,cartesian_product_view::iterator)
`constexpr auto operator*() const;
`
[11](#range.cartesian.iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17035)
*Effects*: Equivalent to:return *tuple-transform*([](auto& i) -> decltype(auto) { return *i; }, *current_*);
[🔗](#lib:operator++,cartesian_product_view::iterator)
`constexpr iterator& operator++();
`
[12](#range.cartesian.iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17049)
*Effects*: Equivalent to:*next*();return *this;
[🔗](#lib:operator++,cartesian_product_view::iterator_)
`constexpr void operator++(int);
`
[13](#range.cartesian.iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17064)
*Effects*: Equivalent to ++*this[.](#range.cartesian.iterator-13.sentence-1)
[🔗](#lib:operator++,cartesian_product_view::iterator__)
`constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<maybe-const<Const, First>>;
`
[14](#range.cartesian.iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17075)
*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,cartesian_product_view::iterator)
`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](#range.cartesian.iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17092)
*Effects*: Equivalent to:*prev*();return *this;
[🔗](#lib:operator--,cartesian_product_view::iterator_)
`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](#range.cartesian.iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17108)
*Effects*: Equivalent to:auto tmp = *this;--*this;return tmp;
[🔗](#lib:operator+=,cartesian_product_view::iterator)
`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](#range.cartesian.iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17125)
Let orig be the value of *this before the call[.](#range.cartesian.iterator-17.sentence-1)
Let ret be:
- [(17.1)](#range.cartesian.iterator-17.1)
If x > 0,
the value of *this had *next* been called x times[.](#range.cartesian.iterator-17.1.sentence-1)
- [(17.2)](#range.cartesian.iterator-17.2)
Otherwise, if x < 0,
the value of *this had *prev* been called -x times[.](#range.cartesian.iterator-17.2.sentence-1)
- [(17.3)](#range.cartesian.iterator-17.3)
Otherwise, orig[.](#range.cartesian.iterator-17.3.sentence-1)
[18](#range.cartesian.iterator-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17140)
*Preconditions*: x is in the range[ranges::distance(*this, ranges::begin(**parent_*)),
ranges::distance(*this, ranges::end(**parent_*))][.](#range.cartesian.iterator-18.sentence-1)
[19](#range.cartesian.iterator-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17146)
*Effects*: Sets the value of *this to ret[.](#range.cartesian.iterator-19.sentence-1)
[20](#range.cartesian.iterator-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17150)
*Returns*: *this[.](#range.cartesian.iterator-20.sentence-1)
[21](#range.cartesian.iterator-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17154)
*Complexity*: Constant[.](#range.cartesian.iterator-21.sentence-1)
[🔗](#lib:operator-=,cartesian_product_view::iterator)
`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](#range.cartesian.iterator-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17166)
*Effects*: Equivalent to:*this += -x;return *this;
[🔗](#lib:operator%5b%5d,cartesian_product_view::iterator)
`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](#range.cartesian.iterator-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17182)
*Effects*: Equivalent to: return *((*this) + n);
[🔗](#lib:operator==,cartesian_product_view::iterator)
`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](#range.cartesian.iterator-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17194)
*Effects*: Equivalent to: return x.*current_* == y.*current_*;
[🔗](#lib:operator==,cartesian_product_view::iterator_)
`friend constexpr bool operator==(const iterator& x, default_sentinel_t);
`
[25](#range.cartesian.iterator-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17205)
*Returns*: true if std::get<i>(x.*current_*) == ranges::end(std::get<i>(x.*parent_*->*bases_*)) is true for any integer 0 ≤ i ≤ sizeof...(Vs);
otherwise, false[.](#range.cartesian.iterator-25.sentence-1)
[🔗](#lib:operator%3c=%3e,cartesian_product_view::iterator)
`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](#range.cartesian.iterator-26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17220)
*Effects*: Equivalent to: return x.*current_* <=> y.*current_*;
[🔗](#lib:operator+,cartesian_product_view::iterator)
`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](#range.cartesian.iterator-27)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17232)
*Effects*: Equivalent to: return *iterator*(x) += y;
[🔗](#lib:operator+,cartesian_product_view::iterator_)
`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](#range.cartesian.iterator-28)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17244)
*Effects*: Equivalent to: return y + x;
[🔗](#lib:operator-,cartesian_product_view::iterator)
`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](#range.cartesian.iterator-29)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17256)
*Effects*: Equivalent to: return *iterator*(x) -= y;
[🔗](#lib:operator-,cartesian_product_view::iterator_)
`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](#range.cartesian.iterator-30)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17268)
*Effects*: Equivalent to: return x.*distance-from*(y.*current_*);
[🔗](#lib:operator-,cartesian_product_view::iterator__)
`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](#range.cartesian.iterator-31)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17280)
Let *end-tuple* be an object of a type
that is a specialization of tuple, such that:
- [(31.1)](#range.cartesian.iterator-31.1)
std::get<0>(*end-tuple*) has the same value asranges::end(std::get<0>(i.*parent_*->*bases_*));
- [(31.2)](#range.cartesian.iterator-31.2)
std::get<N>(*end-tuple*) has the same value asranges::begin(std::get<N>(i.*parent_*->*bases_*)) for every integer 1 ≤ N ≤ sizeof...(Vs)[.](#range.cartesian.iterator-31.sentence-1)
[32](#range.cartesian.iterator-32)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17293)
*Effects*: Equivalent to: return i.*distance-from*(*end-tuple*);
[🔗](#lib:operator-,cartesian_product_view::iterator___)
`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](#range.cartesian.iterator-33)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17305)
*Effects*: Equivalent to: return -(i - s);
[🔗](#lib:iter_move,cartesian_product_view::iterator)
`friend constexpr auto iter_move(const iterator& i) noexcept(see below);
`
[34](#range.cartesian.iterator-34)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17316)
*Effects*: Equivalent to: return *tuple-transform*(ranges::iter_move, i.*current_*);
[35](#range.cartesian.iterator-35)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17320)
*Remarks*: The exception specification is equivalent to
the logical and of the following expressions:
- [(35.1)](#range.cartesian.iterator-35.1)
noexcept(ranges::iter_move(std::get<N>(i.*current_*))) for every integer
0 ≤ N ≤ sizeof...(Vs),
- [(35.2)](#range.cartesian.iterator-35.2)
is_nothrow_move_constructible_v<range_rvalue_reference_t<*maybe-const*<Const, T>>>
for every type T in First, Vs...[.](#range.cartesian.iterator-35.sentence-1)
[🔗](#lib:iter_swap,cartesian_product_view::iterator)
`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](#range.cartesian.iterator-36)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17342)
*Effects*: For every integer 0 ≤ i ≤ sizeof...(Vs), performs:ranges::iter_swap(std::get<i>(l.*current_*), std::get<i>(r.*current_*))
[37](#range.cartesian.iterator-37)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17349)
*Remarks*: The exception specification is equivalent to the logical and of the following expressions:
- [(37.1)](#range.cartesian.iterator-37.1)
noexcept(ranges::iter_swap(std::get<i>(l.*current_*), std::get<i>(r.*current_*))) for
every integer 0 ≤ i ≤ sizeof...(Vs)[.](#range.cartesian.iterator-37.sentence-1)
### [25.7.34](#range.cache.latest) Cache latest view [[range.cache.latest]](range.cache.latest)
#### [25.7.34.1](#range.cache.latest.overview) Overview [[range.cache.latest.overview]](range.cache.latest.overview)
[1](#range.cache.latest.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17363)
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[.](#range.cache.latest.overview-1.sentence-1)
[*Note [1](#range.cache.latest.overview-note-1)*:
This is useful if computation of the element to produce is expensive[.](#range.cache.latest.overview-1.sentence-2)
— *end note*]
[2](#range.cache.latest.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17371)
The name views::cache_latest denotes
a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.cache.latest.overview-2.sentence-1)
Let E be an expression[.](#range.cache.latest.overview-2.sentence-2)
The expression views::cache_latest(E) is expression-equivalent tocache_latest_view(E)[.](#range.cache.latest.overview-2.sentence-3)
#### [25.7.34.2](#range.cache.latest.view) Class template cache_latest_view [[range.cache.latest.view]](range.cache.latest.view)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V>class [cache_latest_view](#lib:cache_latest_view "25.7.34.2Class template cache_­latest_­view[range.cache.latest.view]") : public view_interface<cache_latest_view<V>> { V *base_* = V(); // *exposition only*using *cache-t* = conditional_t<is_reference_v<range_reference_t<V>>, // *exposition only* add_pointer_t<range_reference_t<V>>,
range_reference_t<V>>; *non-propagating-cache*<*cache-t*> *cache_*; // *exposition only*// [[range.cache.latest.iterator]](#range.cache.latest.iterator "25.7.34.3Class cache_­latest_­view::iterator"), class cache_latest_view::*iterator*class *iterator*; // *exposition only*// [[range.cache.latest.sentinel]](#range.cache.latest.sentinel "25.7.34.4Class cache_­latest_­view::sentinel"), class cache_latest_view::*sentinel*class *sentinel*; // *exposition only*public: cache_latest_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> = default; constexpr explicit cache_latest_view(V base); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr auto begin(); constexpr auto end(); 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>; 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>; }; template<class R> cache_latest_view(R&&) -> cache_latest_view<views::all_t<R>>;}
[🔗](#lib:cache_latest_view,constructor)
`constexpr explicit cache_latest_view(V base);
`
[1](#range.cache.latest.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17425)
*Effects*: Initializes *base_* with std::move(base)[.](#range.cache.latest.view-1.sentence-1)
[🔗](#lib:begin,cache_latest_view)
`constexpr auto begin();
`
[2](#range.cache.latest.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17436)
*Effects*: Equivalent to: return *iterator*(*this);
[🔗](#lib:end,cache_latest_view)
`constexpr auto end();
`
[3](#range.cache.latest.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17447)
*Effects*: Equivalent to: return *sentinel*(*this);
[🔗](#lib:size,cache_latest_view)
`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](#range.cache.latest.view-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17459)
*Effects*: Equivalent to: return ranges::size(*base_*);
[🔗](#lib:reserve_hint,cache_latest_view)
`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](#range.cache.latest.view-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17471)
*Effects*: Equivalent to: return ranges::reserve_hint(*base_*);
#### [25.7.34.3](#range.cache.latest.iterator) Class cache_latest_view::*iterator* [[range.cache.latest.iterator]](range.cache.latest.iterator)
[🔗](#lib:cache_latest_view::iiterator)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V>class cache_latest_view<V>::*iterator* { cache_latest_view* *parent_*; // *exposition only* iterator_t<V> *current_*; // *exposition only*constexpr explicit *iterator*(cache_latest_view& parent); // *exposition only*public:using difference_type = range_difference_t<V>; using value_type = range_value_t<V>; using iterator_concept = input_iterator_tag; *iterator*(*iterator*&&) = default; *iterator*& operator=(*iterator*&&) = default; constexpr iterator_t<V> base() &&; constexpr const iterator_t<V>& base() const & noexcept; constexpr range_reference_t<V>& operator*() const; constexpr *iterator*& operator++(); constexpr void operator++(int); friend constexpr range_rvalue_reference_t<V> iter_move(const *iterator*& i)noexcept(noexcept(ranges::iter_move(i.*current_*))); friend constexpr void iter_swap(const *iterator*& x, const *iterator*& y)noexcept(noexcept(ranges::iter_swap(x.*current_*, y.*current_*)))requires [indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<V>>; };}
[🔗](#lib:cache_latest_view::iterator,constructor)
`constexpr explicit iterator(cache_latest_view& parent);
`
[1](#range.cache.latest.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17521)
*Effects*: Initializes *current_* withranges::begin(parent.*base_*) and *parent_* with addressof(parent)[.](#range.cache.latest.iterator-1.sentence-1)
[🔗](#lib:base,cache_latest_view::iterator)
`constexpr iterator_t<V> base() &&;
`
[2](#range.cache.latest.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17534)
*Returns*: std::move(*current_*)[.](#range.cache.latest.iterator-2.sentence-1)
[🔗](#lib:base,cache_latest_view::iterator_)
`constexpr const iterator_t<V>& base() const & noexcept;
`
[3](#range.cache.latest.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17545)
*Returns*: *current_*[.](#range.cache.latest.iterator-3.sentence-1)
[🔗](#lib:operator++,cache_latest_view::iterator)
`constexpr iterator& operator++();
`
[4](#range.cache.latest.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17556)
*Effects*: Equivalent to:*parent_*->*cache_*.reset();++*current_*;return *this;
[🔗](#lib:operator++,cache_latest_view::iterator_)
`constexpr void operator++(int);
`
[5](#range.cache.latest.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17572)
*Effects*: Equivalent to: ++*this[.](#range.cache.latest.iterator-5.sentence-1)
[🔗](#lib:operator*,cache_latest_view::iterator)
`constexpr range_reference_t<V>& operator*() const;
`
[6](#range.cache.latest.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17583)
*Effects*: Equivalent to:if constexpr (is_reference_v<range_reference_t<V>>) {if (!*parent_*->*cache_*) {*parent_*->*cache_* = addressof(*as-lvalue*(**current_*)); }return ***parent_*->*cache_*;} else {if (!*parent_*->c*ache_*) {*parent_*->*cache_*.*emplace-deref*(*current_*); }return **parent_*->*cache_*;}
[*Note [1](#range.cache.latest.iterator-note-1)*:
Evaluations of operator* on the same iterator object
can conflict ([[intro.races]](intro.races "6.10.2.2Data races"))[.](#range.cache.latest.iterator-6.sentence-1)
— *end note*]
[🔗](#lib:iter_move,cache_latest_view::iterator)
`friend constexpr range_rvalue_reference_t<V> iter_move(const iterator& i)
noexcept(noexcept(ranges::iter_move(i.current_)));
`
[7](#range.cache.latest.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17612)
*Effects*: Equivalent to: return ranges::iter_move(i.*current_*);
[🔗](#lib:iter_swap,cache_latest_view::iterator)
`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](#range.cache.latest.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17625)
*Effects*: Equivalent toranges::iter_swap(x.*current_*, y.*current_*)[.](#range.cache.latest.iterator-8.sentence-1)
#### [25.7.34.4](#range.cache.latest.sentinel) Class cache_latest_view::*sentinel* [[range.cache.latest.sentinel]](range.cache.latest.sentinel)
[🔗](#lib:cache_latest_view::sentinel)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V>class cache_latest_view<V>::*sentinel* { sentinel_t<V> *end_* = sentinel_t<V>(); // *exposition only*constexpr explicit *sentinel*(cache_latest_view& parent); // *exposition only*public:*sentinel*() = default; constexpr sentinel_t<V> base() const; friend constexpr bool operator==(const *iterator*& x, const *sentinel*& y); 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>>; 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>>; };}
[🔗](#lib:cache_latest_view::sentinel,constructor)
`constexpr explicit sentinel(cache_latest_view& parent);
`
[1](#range.cache.latest.sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17664)
*Effects*: Initializes *end_* with ranges::end(parent.*base_*)[.](#range.cache.latest.sentinel-1.sentence-1)
[🔗](#lib:base,cache_latest_view::sentinel)
`constexpr sentinel_t<V> base() const;
`
[2](#range.cache.latest.sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17675)
*Returns*: *end_*[.](#range.cache.latest.sentinel-2.sentence-1)
[🔗](#lib:operator==,cache_latest_view::iterator)
`friend constexpr bool operator==(const iterator& x, const sentinel& y);
`
[3](#range.cache.latest.sentinel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17687)
*Returns*: x.*current_* == y.*end_*[.](#range.cache.latest.sentinel-3.sentence-1)
[🔗](#lib:operator-,cache_latest_view::iterator)
`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](#range.cache.latest.sentinel-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17700)
*Returns*: x.*current_* - y.*end_*[.](#range.cache.latest.sentinel-4.sentence-1)
[🔗](#lib:operator-,cache_latest_view::iterator_)
`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](#range.cache.latest.sentinel-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17713)
*Returns*: x.*end_* - y.*current_*[.](#range.cache.latest.sentinel-5.sentence-1)
### [25.7.35](#range.to.input) To input view [[range.to.input]](range.to.input)
#### [25.7.35.1](#range.to.input.overview) Overview [[range.to.input.overview]](range.to.input.overview)
[1](#range.to.input.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17722)
to_input_view presents a view of an underlying sequence
as an input-only non-common range[.](#range.to.input.overview-1.sentence-1)
[*Note [1](#range.to.input.overview-note-1)*:
This is useful to avoid overhead
that can be necessary to provide support for the operations
needed for greater iterator strength[.](#range.to.input.overview-1.sentence-2)
— *end note*]
[2](#range.to.input.overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17731)
The name views::to_input denotes
a range adaptor object ([[range.adaptor.object]](#range.adaptor.object "25.7.2Range adaptor objects"))[.](#range.to.input.overview-2.sentence-1)
Let E be an expression and let T be decltype((E))[.](#range.to.input.overview-2.sentence-2)
The expression views::to_input(E) is expression-equivalent to:
- [(2.1)](#range.to.input.overview-2.1)
views::all(E) if T models [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]"),
does not satisfy [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]"), and
does not satisfy [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")[.](#range.to.input.overview-2.1.sentence-1)
- [(2.2)](#range.to.input.overview-2.2)
Otherwise, to_input_view(E)[.](#range.to.input.overview-2.2.sentence-1)
#### [25.7.35.2](#range.to.input.view) Class template to_input_view [[range.to.input.view]](range.to.input.view)
[🔗](#lib:to_input_view)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V>class to_input_view : public view_interface<to_input_view<V>> { V *base_* = V(); // *exposition only*// [[range.to.input.iterator]](#range.to.input.iterator "25.7.35.3Class template to_­input_­view::iterator"), class template to_input_view::*iterator*template<bool Const> class *iterator*; // *exposition only*public: to_input_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> = default; constexpr explicit to_input_view(V base); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr auto begin() requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>); constexpr auto begin() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V>; 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>; 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>; 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>; }; template<class R> to_input_view(R&&) -> to_input_view<views::all_t<R>>;}
[🔗](#lib:to_input_view,constructor)
`constexpr explicit to_input_view(V base);
`
[1](#range.to.input.view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17790)
*Effects*: Initializes *base_* with std::move(base)[.](#range.to.input.view-1.sentence-1)
[🔗](#lib:begin,to_input_view)
`constexpr auto begin() requires (![simple-view](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V>);
`
[2](#range.to.input.view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17801)
*Effects*: Equivalent to: return *iterator*<false>(ranges::begin(*base_*));
[🔗](#lib:begin,to_input_view_)
`constexpr auto begin() const requires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const V>;
`
[3](#range.to.input.view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17812)
*Effects*: Equivalent to: return *iterator*<true>(ranges::begin(*base_*));
[🔗](#lib:end,to_input_view)
`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](#range.to.input.view-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17824)
*Effects*: Equivalent to: return ranges::end(*base_*);
[🔗](#lib:size,to_input_view)
`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](#range.to.input.view-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17836)
*Effects*: Equivalent to: return ranges::size(*base_*);
[🔗](#lib:reserve_hint,to_input_view)
`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](#range.to.input.view-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17848)
*Effects*: Equivalent to: return ranges::reserve_hint(*base_*);
#### [25.7.35.3](#range.to.input.iterator) Class template to_input_view::*iterator* [[range.to.input.iterator]](range.to.input.iterator)
[🔗](#lib:to_input_view::iterator)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V>template<bool Const>class to_input_view<V>::*iterator* {using *Base* = *maybe-const*<Const, V>; // *exposition only* iterator_t<*Base*> *current_* = iterator_t<*Base*>(); // *exposition only*constexpr explicit *iterator*(iterator_t<*Base*> current); // *exposition only*public:using difference_type = range_difference_t<*Base*>; using value_type = range_value_t<*Base*>; using iterator_concept = input_iterator_tag; *iterator*() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<iterator_t<*Base*>> = default; *iterator*(*iterator*&&) = default; *iterator*& operator=(*iterator*&&) = default; 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*>>; 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](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<*Base*>, iterator_t<*Base*>>; 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*>>; 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](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<*Base*>>; };}
[🔗](#lib:to_input_view::iterator,constructor)
`constexpr explicit iterator(iterator_t<Base> current);
`
[1](#range.to.input.iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17912)
*Effects*: Initializes *current_* with std::move(current)[.](#range.to.input.iterator-1.sentence-1)
[🔗](#lib:to_input_view::iterator,constructor_)
`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](#range.to.input.iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17924)
*Effects*: Initializes *current_* with std::move(i.*current_*)[.](#range.to.input.iterator-2.sentence-1)
[🔗](#lib:base,to_input_view::iterator)
`constexpr iterator_t<Base> base() &&;
`
[3](#range.to.input.iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17935)
*Returns*: std::move(*current_)*[.](#range.to.input.iterator-3.sentence-1)
[🔗](#lib:base,to_input_view::iterator_)
`constexpr const iterator_t<Base>& base() const & noexcept;
`
[4](#range.to.input.iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17946)
*Returns*: *current_*[.](#range.to.input.iterator-4.sentence-1)
[🔗](#lib:operator++,to_input_view::iterator)
`constexpr iterator& operator++();
`
[5](#range.to.input.iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17957)
*Effects*: Equivalent to:++*current_*;return *this;
[🔗](#lib:operator++,to_input_view::iterator_)
`constexpr void operator++(int);
`
[6](#range.to.input.iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17972)
*Effects*: Equivalent to: ++*this;
[🔗](#lib:operator==,to_input_view::iterator)
`friend constexpr bool operator==(const iterator& x, const sentinel_t<Base>& y);
`
[7](#range.to.input.iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17983)
*Returns*: x.*current_* == y[.](#range.to.input.iterator-7.sentence-1)
[🔗](#lib:operator-,to_input_view::iterator)
`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](#range.to.input.iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17995)
*Returns*: y - x.*current_*[.](#range.to.input.iterator-8.sentence-1)
[🔗](#lib:operator-,to_input_view::iterator_)
`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](#range.to.input.iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L18007)
*Returns*: x.*current_* - y[.](#range.to.input.iterator-9.sentence-1)
[🔗](#lib:iter_move,to_input_view::iterator)
`friend constexpr range_rvalue_reference_t<Base> iter_move(const iterator& i)
noexcept(noexcept(ranges::iter_move(i.current_)));
`
[10](#range.to.input.iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L18019)
*Effects*: Equivalent to: return ranges::iter_move(i.*current_*);
[🔗](#lib:iter_swap,to_input_view::iterator)
`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](#range.to.input.iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L18032)
*Effects*: Equivalent to: ranges::iter_swap(x.*current_*, y.*current_*);