This commit is contained in:
2025-10-25 03:02:53 +03:00
commit 043225d523
3416 changed files with 681196 additions and 0 deletions

627
cppdraft/range/cartesian.md Normal file
View File

@@ -0,0 +1,627 @@
[range.cartesian]
# 25 Ranges library [[ranges]](./#ranges)
## 25.7 Range adaptors [[range.adaptors]](range.adaptors#range.cartesian)
### 25.7.33 Cartesian product view [range.cartesian]
#### [25.7.33.1](#overview) Overview [[range.cartesian.overview]](range.cartesian.overview)
[1](#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[.](#overview-1.sentence-1)
[2](#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"))[.](#overview-2.sentence-1)
Given a pack of subexpressions Es,
the expression views::cartesian_product(Es...) is expression-equivalent to
- [(2.1)](#overview-2.1)
views::single(tuple()) if Es is an empty pack,
- [(2.2)](#overview-2.2)
otherwise,cartesian_product_view<views::all_t<decltype((Es))>...>(Es...)[.](#overview-2.sentence-2)
[3](#overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16581)
[*Example [1](#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](#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]](#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](#view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16685)
*Effects*: Initializes *bases_* with std::move(first_base), std::move(bases)...[.](#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](#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](#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](#view-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16731)
Let:
- [(4.1)](#view-4.1)
*is-const* be true for the const-qualified overload, andfalse otherwise;
- [(4.2)](#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)](#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[.](#view-4.sentence-1)
[5](#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](#view-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16765)
*Returns*: default_sentinel[.](#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](#view-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16779)
The return type is an implementation-defined unsigned-integer-like type[.](#view-7.sentence-1)
[8](#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[.](#view-8.sentence-1)
[9](#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_*[.](#view-9.sentence-1)
[10](#view-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16791)
*Preconditions*: p can be represented by the return type[.](#view-10.sentence-1)
[11](#view-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16795)
*Returns*: p[.](#view-11.sentence-1)
#### [25.7.33.3](#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*](range.adaptor.helpers#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](#iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16891)
*iterator*::iterator_concept is defined as follows:
- [(1.1)](#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[.](#iterator-1.1.sentence-1)
- [(1.2)](#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[.](#iterator-1.2.sentence-1)
- [(1.3)](#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[.](#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#L16911)
*iterator*::difference_type is
an implementation-defined
signed-integer-like type[.](#iterator-2.sentence-1)
[3](#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[.](#iterator-3.sentence-1)
[🔗](#lib:next,cartesian_product_view)
`template<size_t N = sizeof...(Vs)>
constexpr void next();
`
[4](#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](#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](#iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16975)
Let:
- [(6.1)](#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)](#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)](#iterator-6.3)
*scaled-sum* be the sum of *scaled-distance*(N) for every integer 0 ≤ N ≤ sizeof...(Vs)[.](#iterator-6.sentence-1)
[7](#iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16991)
*Preconditions*: *scaled-sum* can be represented by difference_type[.](#iterator-7.sentence-1)
[8](#iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16995)
*Returns*: *scaled-sum*[.](#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](#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)[.](#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](#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_*)[.](#iterator-10.sentence-1)
[🔗](#lib:operator*,cartesian_product_view::iterator)
`constexpr auto operator*() const;
`
[11](#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](#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](#iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17064)
*Effects*: Equivalent to ++*this[.](#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](#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](#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](#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](#iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17125)
Let orig be the value of *this before the call[.](#iterator-17.sentence-1)
Let ret be:
- [(17.1)](#iterator-17.1)
If x > 0,
the value of *this had *next* been called x times[.](#iterator-17.1.sentence-1)
- [(17.2)](#iterator-17.2)
Otherwise, if x < 0,
the value of *this had *prev* been called -x times[.](#iterator-17.2.sentence-1)
- [(17.3)](#iterator-17.3)
Otherwise, orig[.](#iterator-17.3.sentence-1)
[18](#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_*))][.](#iterator-18.sentence-1)
[19](#iterator-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17146)
*Effects*: Sets the value of *this to ret[.](#iterator-19.sentence-1)
[20](#iterator-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17150)
*Returns*: *this[.](#iterator-20.sentence-1)
[21](#iterator-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L17154)
*Complexity*: Constant[.](#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](#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](#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](#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](#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[.](#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](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, First, Vs...>;
`
[26](#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](#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](#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](#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](#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](#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)](#iterator-31.1)
std::get<0>(*end-tuple*) has the same value asranges::end(std::get<0>(i.*parent_*->*bases_*));
- [(31.2)](#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)[.](#iterator-31.sentence-1)
[32](#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](#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](#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](#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)](#iterator-35.1)
noexcept(ranges::iter_move(std::get<N>(i.*current_*))) for every integer
0 ≤ N ≤ sizeof...(Vs),
- [(35.2)](#iterator-35.2)
is_nothrow_move_constructible_v<range_rvalue_reference_t<*maybe-const*<Const, T>>>
for every type T in First, Vs...[.](#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](#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](#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)](#iterator-37.1)
noexcept(ranges::iter_swap(std::get<i>(l.*current_*), std::get<i>(r.*current_*))) for
every integer 0 ≤ i ≤ sizeof...(Vs)[.](#iterator-37.sentence-1)