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.

### 3760. `cartesian_product_view::iterator`'s `parent_` is never valid

Section: 26.7.31 [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.

1. Modify 26.7.31.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:

   > > 1. (4.1) — `is-const` be `true` for the const-qualified overload, and `false` otherwise;

   > > 2. (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

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

2. Modify 26.7.31.3 [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

   > >         constexpr explicit iterator(Parent& parent, tuple<iterator_t<maybe-const<Const, First>>,
   > >           iterator_t<maybe-const<Const, Vs>>...> current);                   // exposition only
   > >       };
   > >     }

   > […]

   >     constexpr explicit iterator(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_)`.