zip_view::iterator
's operator<=>
is overconstrainedSection: 25.7.25.3 [range.zip.iterator] Status: C++23 Submitter: S. B. Tam Opened: 2022-04-21 Last modified: 2023-11-22
Priority: Not Prioritized
View all issues with C++23 status.
Discussion:
zip_view::iterator
's operator<=>
is constrained with
(three_way_comparable<iterator_t<maybe-const<Const, Views>>> && ...)
.
This is unnecessary, because the comparison is performed on the stored tuple-or-pair
,
and both std::tuple
and std::pair
provide operator<=>
regardless of
whether the elements are three-way comparable.
std::tuple
nor std::pair
provides operator<
since C++20, comparing two zip::iterator
s with operator<
(which is specified
to return x.current_ < y.current_
, where current_
is a
tuple-or-pair
) eventually uses tuple
or pair
's operator<=>
anyway.
Thus, I think it's possible to make operator<=>
not require three_way_comparable
.
This also makes it possible to remove the operator functions for <
, >
, <=
,
>=
and rely on the operators synthesized from operator<=>
.
[2022-04-24; Daniel comments and provides wording]
It should be pointed out that by still constraining operator<=>
with
all-random-access<Const, Views...>
we also constrain by
random_access_iterator<iterator_t<maybe-const<Const, Views>>>
which again means that we constrain by
totally_ordered<iterator_t<maybe-const<Const, Views>>>
, so
this operator will only be satisfied with iterators I
that satisfy
partially-ordered-with<I, I>
. Based on this argument the delegation to
tuple-or-pair
's operator<=>
that solely depends on
synth-three-way
should be appropriate.
[2022-05-17; Reflector poll]
Set status to Tentatively Ready after six votes in favour during reflector poll.
[2022-07-15; LWG telecon: move to Ready]
[2022-07-25 Approved at July 2022 virtual plenary. Status changed: Ready → WP.]
Proposed resolution:
This wording is relative to N4910.
Modify 25.7.25.3 [range.zip.iterator] as indicated:
[…]namespace std::ranges { […] template<input_range... Views> requires (view<Views> && ...) && (sizeof...(Views) > 0) template<bool Const> class zip_view<Views...>::iterator { tuple-or-pair<iterator_t<maybe-const<Const, Views>>...> current_; // exposition only constexpr explicit iterator(tuple-or-pair<iterator_t<maybe-const<Const, Views>>...>); // exposition only public: […] friend constexpr bool operator==(const iterator& x, const iterator& y) requires (equality_comparable<iterator_t<maybe-const<Const, Views>>> && ...);friend constexpr bool operator<(const iterator& x, const iterator& y) requires all-random-access<Const, Views...>; friend constexpr bool operator>(const iterator& x, const iterator& y) requires all-random-access<Const, Views...>; friend constexpr bool operator<=(const iterator& x, const iterator& y) requires all-random-access<Const, Views...>; friend constexpr bool operator>=(const iterator& x, const iterator& y) requires all-random-access<Const, Views...>;friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires all-random-access<Const, Views...>&& three_way_comparable<iterator_t<maybe-const<Const, Views>>> && ...); […] }; […] }friend constexpr bool operator<(const iterator& x, const iterator& y) requires all-random-access<Const, Views...>;
-16- Returns:x.current_ < y.current_
.friend constexpr bool operator>(const iterator& x, const iterator& y) requires all-random-access<Const, Views...>;
-17- Effects: Equivalent to:return y < x;
friend constexpr bool operator<=(const iterator& x, const iterator& y) requires all-random-access<Const, Views...>;
-18- Effects: Equivalent to:return !(y < x);
friend constexpr bool operator>=(const iterator& x, const iterator& y) requires all-random-access<Const, Views...>;
-19- Effects: Equivalent to:return !(x < y);
friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires all-random-access<Const, Views...>&& (three_way_comparable<iterator_t<maybe-const<Const, Views>>> && ...);-20- Returns:
x.current_ <=> y.current_
.