[range.cartesian] (original) (raw)

25.7.33.1 Overview [range.cartesian.overview]

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.

Given a pack of subexpressions Es, the expression views​::​cartesian_product(Es...)is expression-equivalent to

[Example 1: vector<int> v { 0, 1, 2 };for (auto&& [a, b, c] : views::cartesian_product(v, v, v)) { cout << a << ' ' << b << ' ' << c << '\n';} — _end example_]

25.7.33.2 Class template cartesian_product_view [range.cartesian.view]

namespace std::ranges { template<bool Const, class First, class... Vs> concept cartesian-product-is-random-access = (random_access_range<_maybe-const_<Const, First>> && ... && (random_access_range<_maybe-const_<Const, Vs>> && sized_range<_maybe-const_<Const, Vs>>));template<class R> concept cartesian-product-common-arg = common_range<R> || (sized_range<R> && random_access_range<R>);template<bool Const, class First, class... Vs> concept cartesian-product-is-bidirectional = (bidirectional_range<_maybe-const_<Const, First>> && ... && (bidirectional_range<_maybe-const_<Const, Vs>> && cartesian-product-common-arg<_maybe-const_<Const, Vs>>));template<class First, class...> concept cartesian-product-is-common = cartesian-product-common-arg<First>;template<class... Vs> concept cartesian-product-is-sized = (sized_range<Vs> && ...);template<bool Const, template<class> class FirstSent, class First, class... Vs> concept cartesian-is-sized-sentinel = (sized_sentinel_for<FirstSent<_maybe-const_<Const, First>>, iterator_t<_maybe-const_<Const, First>>> && ... && (sized_range<_maybe-const_<Const, Vs>> && sized_sentinel_for<iterator_t<_maybe-const_<Const, Vs>>, iterator_t<_maybe-const_<Const, Vs>>>));template<cartesian-product-common-arg R> constexpr auto cartesian-common-arg-end(R& r) { if constexpr (common_range<R>) { return ranges::end(r);} else { return ranges::begin(r) + ranges::distance(r);} } template<input_range First, forward_range... Vs> requires (view<First> && ... && view<Vs>) class cartesian_product_view : public view_interface<cartesian_product_view<First, Vs...>> { private: tuple<First, Vs...> bases_; template<bool Const> class iterator; public: constexpr cartesian_product_view() = default;constexpr explicit cartesian_product_view(First first_base, Vs... bases);constexpr iterator<false> begin() requires (_simple-view_<First> || ... || _simple-view_<Vs>);constexpr iterator<true> begin() const requires (range<const First> && ... && range<const Vs>);constexpr iterator<false> end() requires ((_simple-view_<First> || ... || _simple-view_<Vs>) && cartesian-product-is-common<First, Vs...>);constexpr iterator<true> end() const requires cartesian-product-is-common<const First, const Vs...>;constexpr default_sentinel_t end() const noexcept;constexpr see below size() requires cartesian-product-is-sized<First, Vs...>;constexpr see below size() const requires cartesian-product-is-sized<const First, const Vs...>;};template<class... Vs> cartesian_product_view(Vs&&...) -> cartesian_product_view<views::all_t<Vs>...>;}

constexpr explicit cartesian_product_view(First first_base, Vs... bases);

Effects: Initializes _bases__with std​::​move(first_base), std​::​move(bases)....

Effects: Equivalent to:return iterator<false>(*this, tuple-transform(ranges::begin, bases_));

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>);

Effects: Equivalent to:return iterator<true>(*this, tuple-transform(ranges::begin, bases_));

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...>;

Let:

Effects: Equivalent to:iterator<_is-const_> it(*this, tuple-transform( [](auto& rng){ return begin-or-first-end(rng); }, bases_));return it;

constexpr default_sentinel_t end() const noexcept;

Returns: default_sentinel.

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...>;

The return type is an implementation-defined unsigned-integer-like type.

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.

Let p be the product of the sizes of all the ranges in bases_.

Preconditions: p can be represented by the return type.

25.7.33.3 Class template cartesian_product_view​::​iterator [range.cartesian.iterator]

namespace std::ranges { template<input_range First, forward_range... Vs> requires (view<First> && ... && 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<iterator_t<First>, iterator_t<const First>> && ... && convertible_to<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<_maybe-const_<Const, First>>;constexpr iterator& operator--() requires cartesian-product-is-bidirectional<Const, First, Vs...>;constexpr iterator operator--(int) requires cartesian-product-is-bidirectional<Const, First, Vs...>;constexpr iterator& operator+=(difference_type x) requires cartesian-product-is-random-access<Const, First, Vs...>;constexpr iterator& operator-=(difference_type x) requires cartesian-product-is-random-access<Const, First, Vs...>;constexpr reference operator[](difference_type n) const requires cartesian-product-is-random-access<Const, First, Vs...>;friend constexpr bool operator==(const iterator& x, const iterator& y) requires equality_comparable<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<Const, First, Vs...>;friend constexpr iterator operator+(const iterator& x, difference_type y) requires cartesian-product-is-random-access<Const, First, Vs...>;friend constexpr iterator operator+(difference_type x, const iterator& y) requires cartesian-product-is-random-access<Const, First, Vs...>;friend constexpr iterator operator-(const iterator& x, difference_type y) requires cartesian-product-is-random-access<Const, First, Vs...>;friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires cartesian-is-sized-sentinel<Const, iterator_t, First, Vs...>;friend constexpr difference_type operator-(const iterator& i, default_sentinel_t) requires cartesian-is-sized-sentinel<Const, sentinel_t, First, Vs...>;friend constexpr difference_type operator-(default_sentinel_t, const iterator& i) requires cartesian-is-sized-sentinel<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<iterator_t<_maybe-const_<Const, First>>> && ... && indirectly_swappable<iterator_t<_maybe-const_<Const, Vs>>>);private: using Parent = maybe-const<Const, cartesian_product_view>; Parent* parent_ = nullptr; tuple<iterator_t<_maybe-const_<Const, First>>, iterator_t<_maybe-const_<Const, Vs>>...> current_; template<size_t N = sizeof...(Vs)> constexpr void next(); template<size_t N = sizeof...(Vs)> constexpr void prev(); template<class Tuple> constexpr difference_type distance-from(const Tuple& t) const; constexpr iterator(Parent& parent, tuple<iterator_t<_maybe-const_<Const, First>>, iterator_t<_maybe-const_<Const, Vs>>...> current); };}

_iterator_​::​iterator_concept is defined as follows:

_iterator_​::​difference_type is an implementation-defined signed-integer-like type.

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.

template<size_t N = sizeof...(Vs)> constexpr void _next_();

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>();} }

template<size_t N = sizeof...(Vs)> constexpr void _prev_();

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;

template<class Tuple> constexpr difference_type _distance-from_(const Tuple& t) const;

Let:

Preconditions: scaled-sum can be represented by difference_type.

constexpr _iterator_(_Parent_& parent, tuple<iterator_t<_maybe-const_<Const, First>>, iterator_t<_maybe-const_<Const, Vs>>...> current);

Effects: Initializes_parent__ with addressof(parent) and_current__ with std​::​move(current).

constexpr _iterator_(_iterator_<!Const> i) requires Const && ([convertible_to](concept.convertible#concept:convertible%5Fto "18.4.4 Concept convertible_­to [concept.convertible]")<iterator_t<First>, iterator_t<const First>> && ... && [convertible_to](concept.convertible#concept:convertible%5Fto "18.4.4 Concept convertible_­to [concept.convertible]")<iterator_t<Vs>, iterator_t<const Vs>>);

Effects: Initializes_parent__ with i.parent_ and_current__ with std​::​move(i.current_).

constexpr auto operator*() const;

Effects: Equivalent to:return tuple-transform([](auto& i) -> decltype(auto) { return *i; }, current_);

constexpr _iterator_& operator++();

Effects: Equivalent to:next();return *this;

constexpr void operator++(int);

Effects: Equivalent to ++*this.

constexpr _iterator_ operator++(int) requires [forward_range](range.refinements#concept:forward%5Frange "25.4.5 Other range refinements [range.refinements]")<_maybe-const_<Const, First>>;

Effects: Equivalent to:auto tmp = *this;++*this;return tmp;

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...>;

Effects: Equivalent to:prev();return *this;

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...>;

Effects: Equivalent to:auto tmp = *this;--*this;return tmp;

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...>;

Let orig be the value of *this before the call.

Let ret be:

Preconditions: x is in the range[ranges​::​distance(*this, ranges​::​begin(*parent_)),
ranges​::​distance(*this, ranges​::​end(*parent_))].

Effects: Sets the value of *this to ret.

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...>;

Effects: Equivalent to:*this += -x;return *this;

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...>;

Effects: Equivalent to: return *((*this) + n);

friend constexpr bool operator==(const _iterator_& x, const _iterator_& y) requires [equality_comparable](concept.equalitycomparable#concept:equality%5Fcomparable "18.5.4 Concept equality_­comparable [concept.equalitycomparable]")<iterator_t<_maybe-const_<Const, First>>>;

Effects: Equivalent to: return x.current_ == y.current_;

friend constexpr bool operator==(const _iterator_& x, default_sentinel_t);

Returns: true if std​::​get<i>(x.current_) == ranges​::​end(std​::​get<i>(x._parent__->bases_))is truefor any integer 0 ≤ i ≤ sizeof...(Vs); otherwise, false.

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...>;

Effects: Equivalent to: return x.current_ <=> y.current_;

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...>;

Effects: Equivalent to: return iterator(x) += y;

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...>;

Effects: Equivalent to: return y + x;

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...>;

Effects: Equivalent to: return iterator(x) -= y;

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...>;

Effects: Equivalent to: return x.distance-from(y.current_);

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...>;

Let end-tuple be an object of a type that is a specialization of tuple, such that:

Effects: Equivalent to: return i.distance-from(end-tuple);

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...>;

Effects: Equivalent to: return -(i - s);

friend constexpr auto iter_move(const _iterator_& i) noexcept(_see below_);

Effects: Equivalent to: return tuple-transform(ranges​::​iter_move, i.current_);

Remarks: The exception specification is equivalent to the logical and of the following expressions:

friend constexpr void iter_swap(const _iterator_& l, const _iterator_& r) noexcept(_see below_) requires ([indirectly_swappable](alg.req.ind.swap#concept:indirectly%5Fswappable "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%5Fswappable "24.3.7.4 Concept indirectly_­swappable [alg.req.ind.swap]")<iterator_t<_maybe-const_<Const, Vs>>>);

Effects: For every integer 0 ≤ i ≤ sizeof...(Vs), performs:ranges::iter_swap(std::get<i>(l.current_), std::get<i>(r.current_))

Remarks: The exception specification is equivalent to the logical and of the following expressions: