cartesian_product_view::iterator
's parent_
is never validSection: 25.7.33 [range.cartesian] Status: C++23 Submitter: Hewill Kang Opened: 2022-08-27 Last modified: 2023-11-22
Priority: Not Prioritized
View all issues with C++23 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
.
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 25.7.33.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
betrue
for the const-qualified overload, andfalse
otherwise;(4.2) —
is-empty
betrue
if the expressionranges::empty(rng)
istrue
for anyrng
among the underlying ranges except the first one andfalse
otherwise; and(4.3) —
begin-or-first-end(rng)
be expression-equivalent tois-empty ? ranges::begin(rng) : cartesian-common-arg-end(rng)
ifrng
is the first underlying range andranges::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_
withaddressof(parent)
andcurrent_
withstd::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_
withi.parent_
andcurrent_
withstd::move(i.current_)
.