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.

### 3692. `zip_view::iterator`'s `operator<=>` is overconstrained

Section: 26.7.23.3 [range.zip.iterator] Status: WP Submitter: S. B. Tam Opened: 2022-04-21 Last modified: 2022-07-25

Priority: Not Prioritized

View all issues with WP 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.

Note that, because neither `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.

1. Modify 26.7.23.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_`.