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

471 lines
28 KiB
Markdown
Raw 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.zip]
# 25 Ranges library [[ranges]](./#ranges)
## 25.7 Range adaptors [[range.adaptors]](range.adaptors#range.zip)
### 25.7.25 Zip view [range.zip]
#### [25.7.25.1](#overview) Overview [[range.zip.overview]](range.zip.overview)
[1](#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[.](#overview-1.sentence-1)
[2](#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"))[.](#overview-2.sentence-1)
Given a pack of subexpressions Es...,
the expression views::zip(Es...) is expression-equivalent to
- [(2.1)](#overview-2.1)
auto(views::empty<tuple<>>) if Es is an empty pack,
- [(2.2)](#overview-2.2)
otherwise, zip_view<views::all_t<decltype((Es))>...>(Es...)[.](#overview-2.sentence-2)
[*Example [1](#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](#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]](#iterator "25.7.25.3Class template zip_­view::iterator"), class template zip_view::*iterator*template<bool> class *iterator*; // *exposition only*// [[range.zip.sentinel]](#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](#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[.](#view-1.sentence-1)
[*Note [1](#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"))[.](#view-1.sentence-2)
— *end note*]
[🔗](#lib:zip_view,constructor)
`constexpr explicit zip_view(Views... views);
`
[2](#view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11455)
*Effects*: Initializes *views_* with std::move(views)...[.](#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](#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](#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*](range.adaptor.helpers#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; constexpr *iterator*& operator--() requires [*all-bidirectional*](range.adaptor.helpers#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; constexpr *iterator* operator--(int) requires [*all-bidirectional*](range.adaptor.helpers#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; constexpr *iterator*& operator+=(difference_type x)requires [*all-random-access*](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; constexpr *iterator*& operator-=(difference_type x)requires [*all-random-access*](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; constexpr auto operator[](difference_type n) constrequires [*all-random-access*](range.adaptor.helpers#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*](range.adaptor.helpers#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*](range.adaptor.helpers#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*](range.adaptor.helpers#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*](range.adaptor.helpers#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](#iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11540)
*iterator*::iterator_concept is defined as follows:
- [(1.1)](#iterator-1.1)
If [*all-random-access*](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> is modeled,
then iterator_concept denotes random_access_iterator_tag[.](#iterator-1.1.sentence-1)
- [(1.2)](#iterator-1.2)
Otherwise,
if [*all-bidirectional*](range.adaptor.helpers#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> is modeled,
then iterator_concept denotes bidirectional_iterator_tag[.](#iterator-1.2.sentence-1)
- [(1.3)](#iterator-1.3)
Otherwise,
if [*all-forward*](range.adaptor.helpers#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> is modeled,
then iterator_concept denotes forward_iterator_tag[.](#iterator-1.3.sentence-1)
- [(1.4)](#iterator-1.4)
Otherwise, iterator_concept denotes input_iterator_tag[.](#iterator-1.4.sentence-1)
[2](#iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11558)
*iterator*::iterator_category is present
if and only if [*all-forward*](range.adaptor.helpers#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> is modeled[.](#iterator-2.sentence-1)
[3](#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[.](#iterator-3.sentence-1)
[🔗](#lib:zip_view::iterator,constructor)
`constexpr explicit iterator(tuple<iterator_t<maybe-const<Const, Views>>...> current);
`
[4](#iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11573)
*Effects*: Initializes *current_* with std::move(current)[.](#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](#iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11585)
*Effects*: Initializes *current_* with std::move(i.*current_*)[.](#iterator-5.sentence-1)
[🔗](#lib:operator*,izip_view::iterator)
`constexpr auto operator*() const;
`
[6](#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](#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](#iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11625)
*Effects*: Equivalent to ++*this[.](#iterator-8.sentence-1)
[🔗](#lib:operator++,izip_view::iterator__)
`constexpr iterator operator++(int) requires [all-forward](range.adaptor.helpers#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
`
[9](#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](range.adaptor.helpers#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
`
[10](#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](range.adaptor.helpers#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
`
[11](#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](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
`
[12](#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](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
`
[13](#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](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
`
[14](#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](#iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11733)
*Returns*:
- [(15.1)](#iterator-15.1)
x.*current_* == y.*current_* if [*all-bidirectional*](range.adaptor.helpers#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> is true[.](#iterator-15.1.sentence-1)
- [(15.2)](#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[.](#iterator-15.2.sentence-1)
[*Note [1](#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]")[.](#iterator-15.2.sentence-2)
— *end note*]
- [(15.3)](#iterator-15.3)
Otherwise, false[.](#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](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
`
[16](#iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11760)
*Returns*: x.*current_* <=> y.*current_*[.](#iterator-16.sentence-1)
[🔗](#lib:operator+,izip_view::iterator)
`friend constexpr iterator operator+(const iterator& i, difference_type n)
requires [all-random-access](range.adaptor.helpers#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](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
`
[17](#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](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
`
[18](#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](#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_*))[.](#iterator-19.sentence-1)
[20](#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)[.](#iterator-20.sentence-1)
[🔗](#lib:iter_move,izip_view::iterator)
`friend constexpr auto iter_move(const iterator& i) noexcept(see below);
`
[21](#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](#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](#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](#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)[.](#iterator-24.sentence-1)
#### [25.7.25.4](#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](#sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11910)
*Effects*: Initializes *end_* with end[.](#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](#sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11922)
*Effects*: Initializes *end_* with std::move(i.*end_*)[.](#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](#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[.](#sentinel-3.sentence-1)
Otherwise, false[.](#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](#sentinel-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11954)
Let D be the return type[.](#sentinel-4.sentence-1)
Let *DIST*(i) beD(std::get<i>(x.*current_*) - std::get<i>(y.*end_*))[.](#sentinel-4.sentence-2)
[5](#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)[.](#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](#sentinel-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L11975)
*Effects*: Equivalent to: return -(x - y);