Title
cartesian_product_view::iterator's parent_ is never valid
Status
c++23
Section
[range.cartesian]
Submitter
Hewill Kang

Created on 2022-08-27.00:00:00 last changed 12 months ago

Messages

Date: 2022-11-17.00:42:33

Proposed resolution:

This wording is relative to n4917.

  1. Modify [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 [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_).

Date: 2022-11-12.00:00:00

[ 2022-11-12 Approved at November 2022 meeting in Kona. Status changed: Voting → WP. ]

Date: 2022-09-15.00:00:00

[ 2022-09-23; Reflector poll ]

Set status to Tentatively Ready after eight votes in favour during reflector poll.

Date: 2022-08-27.00:00:00

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.

History
Date User Action Args
2023-11-22 15:47:43adminsetstatus: wp -> c++23
2022-11-17 00:42:33adminsetmessages: + msg13067
2022-11-17 00:42:33adminsetstatus: voting -> wp
2022-11-08 03:46:49adminsetstatus: ready -> voting
2022-09-23 15:03:48adminsetmessages: + msg12784
2022-09-23 15:03:48adminsetstatus: new -> ready
2022-09-03 13:49:36adminsetmessages: + msg12728
2022-08-27 00:00:00admincreate