[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...>(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 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 {templateconcept [*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*> && ... &&([random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")<*maybe-const*>&& [sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<*maybe-const*>)); templateconcept [*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]") || ([sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]") && [random_access_range](range.refinements#concept:random_access_range "25.4.6 Other range refinements [range.refinements]")); templateconcept [*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*> && ... &&([bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<*maybe-const*>&& [*cartesian-product-common-arg*](#concept:cartesian-product-common-arg "25.7.33.2 Class template cartesian_­product_­view [range.cartesian.view]")<*maybe-const*>)); templateconcept [*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]"); templateconcept [*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]") && ...); template 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]")>, iterator_t<*maybe-const*>> && ...&& ([sized_range](range.sized#concept:sized_range "25.4.4 Sized ranges [range.sized]")<*maybe-const*>&& [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*>>)); 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]")) {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]") && ... && [view](range.view#concept:view "25.4.5 Views [range.view]"))class cartesian_product_view : public view_interface> {private: tuple *bases_*; // *exposition only*// [[range.cartesian.iterator]](#iterator "25.7.33.3 Class template cartesian_­product_­view​::​iterator"), class template cartesian_product_view​::​*iterator*template class *iterator*; // *exposition only*public:constexpr cartesian_product_view() = default; constexpr explicit cartesian_product_view(First first_base, Vs... bases); constexpr *iterator* begin()requires (![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]") || ... || ![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]")); constexpr *iterator* begin() constrequires ([range](range.range#concept:range "25.4.2 Ranges [range.range]") && ... && [range](range.range#concept:range "25.4.2 Ranges [range.range]")); constexpr *iterator* end()requires ((![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]") || ... || ![*simple-view*](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]")) &&[*cartesian-product-is-common*](#concept:cartesian-product-is-common "25.7.33.2 Class template cartesian_­product_­view [range.cartesian.view]")); constexpr *iterator* end() constrequires [*cartesian-product-is-common*](#concept:cartesian-product-is-common "25.7.33.2 Class template cartesian_­product_­view [range.cartesian.view]"); 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]"); 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]"); }; template cartesian_product_view(Vs&&...) -> cartesian_product_view...>;} [🔗](#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 begin() requires (![simple-view](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]") || ... || ![simple-view](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]")); ` [2](#view-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16698) *Effects*: Equivalent to:return *iterator*(*this, *tuple-transform*(ranges::begin, *bases_*)); [🔗](#lib:begin,cartesian_product_view_) `constexpr iterator begin() const requires ([range](range.range#concept:range "25.4.2 Ranges [range.range]") && ... && [range](range.range#concept:range "25.4.2 Ranges [range.range]")); ` [3](#view-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16713) *Effects*: Equivalent to:return *iterator*(*this, *tuple-transform*(ranges::begin, *bases_*)); [🔗](#lib:end,cartesian_product_view) `constexpr iterator end() requires ((![simple-view](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]") || ... || ![simple-view](range.utility.helpers#concept:simple-view "25.5.2 Helper concepts [range.utility.helpers]")) && [cartesian-product-is-common](#concept:cartesian-product-is-common "25.7.33.2 Class template cartesian_­product_­view [range.cartesian.view]")); constexpr iterator end() const requires [cartesian-product-is-common](#concept:cartesian-product-is-common "25.7.33.2 Class template cartesian_­product_­view [range.cartesian.view]"); ` [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]"); 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]"); ` [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]") && ... && [view](range.view#concept:view "25.4.5 Views [range.view]"))templateclass cartesian_product_view::*iterator* {public:using iterator_category = input_iterator_tag; using iterator_concept = *see below*; using value_type = tuple>, range_value_t<*maybe-const*>...>; using reference = tuple>, range_reference_t<*maybe-const*>...>; using difference_type = *see below*; *iterator*() = default; constexpr *iterator*(*iterator* i) requires Const &&([convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_­to [concept.convertible]"), iterator_t> &&... && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_­to [concept.convertible]"), iterator_t>); 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*>; 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]"); 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]"); 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]"); 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]"); 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]"); 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]")>>; 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]"); 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]"); 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]"); 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]"); 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]"); 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]"); 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]"); 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]")>> && ... &&[indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept indirectly_­swappable [alg.req.ind.swap]")>>); private:using *Parent* = *maybe-const*; // *exposition only**Parent** *parent_* = nullptr; // *exposition only* tuple>, iterator_t<*maybe-const*>...> *current_*; // *exposition only*templateconstexpr void *next*(); // *exposition only*templateconstexpr void *prev*(); // *exposition only*templateconstexpr difference_type *distance-from*(const Tuple& t) const; // *exposition only*constexpr *iterator*(*Parent*& parent, tuple>, iterator_t<*maybe-const*>...> 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]") 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]") is modeled, then iterator_concept denotes bidirectional_iterator_tag[.](#iterator-1.2.sentence-1) - [(1.3)](#iterator-1.3) Otherwise, if *maybe-const* 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 constexpr void next(); ` [4](#iterator-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16931) *Effects*: Equivalent to:auto& it = std::get(*current_*);++it;if constexpr (N > 0) {if (it == ranges::end(std::get(*parent_*->*bases_*))) { it = ranges::begin(std::get(*parent_*->*bases_*)); *next*(); }} [🔗](#lib:prev,cartesian_product_view) `template constexpr void prev(); ` [5](#iterator-5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L16953) *Effects*: Equivalent to:auto& it = std::get(*current_*);if constexpr (N > 0) {if (it == ranges::begin(std::get(*parent_*->*bases_*))) { it = *cartesian-common-arg-end*(std::get(*parent_*->*bases_*)); *prev*(); }}--it; [🔗](#lib:distance-from,cartesian_product_view) `template 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(ranges​::​size(std​::​get<​N>(*parent_*->*bases_*))) andscaled-size(N+1) if N ≤ sizeof...(Vs), otherwise static_cast(1); - [(6.2)](#iterator-6.2) *scaled-distance*(N) be the product ofstatic_cast(std​::​get(*current_*) - std​::​get(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>...> 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 i) requires Const && ([convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_­to [concept.convertible]"), iterator_t> && ... && [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_­to [concept.convertible]"), iterator_t>); ` [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]")>; ` [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]"); ` [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]"); ` [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]"); ` [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]"); ` [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]"); ` [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]")>>; ` [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(x.*current_*) == ranges​::​end(std​::​get(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]"); ` [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]"); ` [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]"); ` [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]"); ` [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]"); ` [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]"); ` [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(*end-tuple*) has the same value asranges​::​begin(std​::​get(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]"); ` [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(i.*current_*))) for every integer 0 ≤ N ≤ sizeof...(Vs), - [(35.2)](#iterator-35.2) is_nothrow_move_constructible_v>> 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]")>> && ... && [indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept indirectly_­swappable [alg.req.ind.swap]")>>); ` [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(l.*current_*), std::get(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(l.*current_*), std​::​get(r.*current_*))) for every integer 0 ≤ i ≤ sizeof...(Vs)[.](#iterator-37.sentence-1)