[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.5 Customization 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.2 Class template cartesian_­product_­view [range.cartesian.view]") = // *exposition only*([random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<*maybe-const*<Const, First>> && ... &&([random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<*maybe-const*<Const, Vs>>&& [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<*maybe-const*<Const, Vs>>)); template<class R>concept [*cartesian-product-common-arg*](#concept:cartesian-product-common-arg "25.7.33.2 Class template cartesian_­product_­view [range.cartesian.view]") = // *exposition only*[common_range](range.refinements#concept:common_range "25.4.6 Other range refinements [range.refinements]")<R> || ([sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<R> && [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other 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.2 Class template cartesian_­product_­view [range.cartesian.view]") = // *exposition only*([bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<*maybe-const*<Const, First>> && ... &&([bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<*maybe-const*<Const, Vs>>&& [*cartesian-product-common-arg*](#concept:cartesian-product-common-arg "25.7.33.2 Class 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.2 Class template cartesian_­product_­view [range.cartesian.view]") = // *exposition only*[*cartesian-product-common-arg*](#concept:cartesian-product-common-arg "25.7.33.2 Class template cartesian_­product_­view [range.cartesian.view]")<First>; template<class... Vs>concept [*cartesian-product-is-sized*](#concept:cartesian-product-is-sized "25.7.33.2 Class template cartesian_­product_­view [range.cartesian.view]") = // *exposition only*([sized_range](range.sized#concept:sized_range "25.4.4 Sized 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.2 Class template cartesian_­product_­view [range.cartesian.view]") = // *exposition only*([sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept 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.4 Sized ranges [range.sized]")<*maybe-const*<Const, Vs>>&& [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8 Concept 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.2 Class 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.6 Other 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.6 Other range refinements [range.refinements]") First, [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")... Vs>requires ([view](range.view#concept:view "25.4.5 Views [range.view]")<First> && ... && [view](range.view#concept:view "25.4.5 Views [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.3 Class 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.2 Helper concepts [range.utility.helpers]")<First> || ... || ![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]")<Vs>); constexpr *iterator*<true> begin() constrequires ([range](range.range#concept:range "25.4.2 Ranges [range.range]")<const First> && ... && [range](range.range#concept:range "25.4.2 Ranges [range.range]")<const Vs>); constexpr *iterator*<false> end()requires ((![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]")<First> || ... || ![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]")<Vs>) &&[*cartesian-product-is-common*](#concept:cartesian-product-is-common "25.7.33.2 Class 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.2 Class 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.2 Class 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.2 Class 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.2 Helper concepts [range.utility.helpers]")<First> || ... || ![simple-view](range.utility.helpers#concept:simple-view "25.5.2 Helper 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.2 Ranges [range.range]")<const First> && ... && [range](range.range#concept:range "25.4.2 Ranges [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.2 Helper concepts [range.utility.helpers]")<First> || ... || ![simple-view](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]")<Vs>)
    && [cartesian-product-is-common](#concept:cartesian-product-is-common "25.7.33.2 Class 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.2 Class 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.2 Class 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.2 Class 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.6 Other range refinements [range.refinements]") First, [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")... Vs>requires ([view](range.view#concept:view "25.4.5 Views [range.view]")<First> && ... && [view](range.view#concept:view "25.4.5 Views [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.4 Concept convertible_­to [concept.convertible]")<iterator_t<First>, iterator_t<const First>> &&... && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept 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.6 Other range refinements [range.refinements]")<*maybe-const*<Const, First>>; constexpr *iterator*& operator--()requires [*cartesian-product-is-bidirectional*](#concept:cartesian-product-is-bidirectional "25.7.33.2 Class 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.2 Class 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.2 Class 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.2 Class 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.2 Class 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.4 Concept 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.5 Range 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.2 Class 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.2 Class 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.2 Class 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.2 Class 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.2 Class 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.2 Class 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.4 Concept indirectly_­swappable [alg.req.ind.swap]")<iterator_t<*maybe-const*<Const, First>>> && ... &&[indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept 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.2 Class 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.2 Class 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.6 Other 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.4 Concept convertible_­to [concept.convertible]")<iterator_t<First>, iterator_t<const First>> &&
    ... && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept 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.6 Other 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.2 Class 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.2 Class 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.2 Class 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.2 Class 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.2 Class 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.4 Concept 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.5 Range 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.2 Class 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.2 Class 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.2 Class 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.2 Class 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.2 Class 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.2 Class 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.4 Concept indirectly_­swappable [alg.req.ind.swap]")<iterator_t<maybe-const<Const, First>>> && ... &&
        [indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept 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)
