This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
Section: 26.7.32 [range.cartesian] Status: WP Submitter: Hewill Kang Opened: 2022-08-27 Last modified: 2022-11-17
Priority: Not Prioritized
View all issues with WP status.
Discussion:
cartesian_product_view::iterator has a pointer member parent_ that points to cartesian_product_view, but its constructor only accepts a tuple of iterators, which makes parent_ always default-initialized to nullptr.
The proposed resolution is to add an aliased Parent parameter to the constructor and initialize parent_ with addressof, as we usually do.[2022-09-23; Reflector poll]
Set status to Tentatively Ready after eight votes in favour during reflector poll.
[2022-11-12 Approved at November 2022 meeting in Kona. Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4917.
Modify 26.7.32.2 [range.cartesian.view] as indicated:
constexpr iterator<false> begin() requires (!simple-view<First> || ... || !simple-view<Vs>);-2- Effects: Equivalent to: return iterator<false>(*this, tuple-transform(ranges::begin, bases_));
constexpr iterator<true> begin() const requires (range<const First> && ... && range<const Vs>);-3- 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...>;-4- Let:
(4.1) — is-const be true for the const-qualified overload, and false otherwise;
(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 and false otherwise; and
(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 and ranges::begin(rng) otherwise.
-5- Effects: Equivalent to:
iterator<is-const> it(*this, tuple-transform( [](auto& rng){ return begin-or-first-end(rng); }, bases_)); return it;
Modify [ranges.cartesian.iterator] as indicated:
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: […] private: using Parent = maybe-const<Const, cartesian_product_view>; // exposition only Parentmaybe-const<Const, cartesian_product_view>* 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(Tuple t); // exposition only constexprexplicititerator(Parent& parent, tuple<iterator_t<maybe-const<Const, First>>, iterator_t<maybe-const<Const, Vs>>...> current); // exposition only }; }[…]
constexprexplicititerator(Parent& parent, tuple<iterator_t<maybe-const<Const, First>>, iterator_t<maybe-const<Const, Vs>>...> current);-10- Effects: Initializes parent_ with addressof(parent) and current_ with std::move(current).
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>>);-11- Effects: Initializes parent_ with i.parent_ and current_ with std::move(i.current_).