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

628 lines
37 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.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)