25 Ranges library [ranges]

25.7 Range adaptors [range.adaptors]

25.7.33 Cartesian product view [range.cartesian]

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 = // exposition only (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 = // exposition only common_range<R> || (sized_range<R> && random_access_range<R>); template<bool Const, class First, class... Vs> concept cartesian-product-is-bidirectional = // exposition only (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 = // exposition only cartesian-product-common-arg<First>; template<class... Vs> concept cartesian-product-is-sized = // exposition only (sized_range<Vs> && ...); template<bool Const, template<class> class FirstSent, class First, class... Vs> concept cartesian-is-sized-sentinel = // exposition only (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) { // exposition only 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_; // exposition only // [range.cartesian.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<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)....
constexpr iterator<false> begin() requires (!simple-view<First> || ... || !simple-view<Vs>);
Effects: Equivalent to: return iterator<false>(*this, tuple-transform(ranges::begin, bases_));
constexpr iterator<true> begin() const requires (range<const First> && ... && range<const Vs>);
Effects: Equivalent to: return iterator<true>(*this, tuple-transform(ranges::begin, bases_));
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...>;
Let:
  • is-const be true for the const-qualified overload, and false otherwise;
  • is-empty be true if the expression ranges​::​empty(rng) is true for any rng among the underlying ranges except the first one and false otherwise; and
  • 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 and ranges​::​begin(rng) otherwise.
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<First, Vs...>; constexpr see below size() const requires cartesian-product-is-sized<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.
Returns: p.