Title
zip_view::iterator's operator<=> is overconstrained
Status
c++23
Section
[range.zip.iterator]
Submitter
S. B. Tam

Created on 2022-04-21.00:00:00 last changed 12 months ago

Messages

Date: 2022-07-25.20:32:58

Proposed resolution:

This wording is relative to N4910.

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

Date: 2022-07-25.00:00:00

[ 2022-07-25 Approved at July 2022 virtual plenary. Status changed: Ready → WP. ]

Date: 2022-07-15.00:00:00

[ 2022-07-15; LWG telecon: move to Ready ]

Date: 2022-05-15.00:00:00

[ 2022-05-17; Reflector poll ]

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

Date: 2022-04-15.00:00:00

[ 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.

Date: 2022-04-21.00:00:00

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::iterators 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<=>.

History
Date User Action Args
2023-11-22 15:47:43adminsetstatus: wp -> c++23
2022-07-25 20:32:58adminsetmessages: + msg12642
2022-07-25 20:32:58adminsetstatus: ready -> wp
2022-07-25 20:28:19adminsetmessages: + msg12616
2022-05-17 11:57:24adminsetmessages: + msg12454
2022-05-17 11:57:24adminsetstatus: new -> ready
2022-04-24 09:39:28adminsetmessages: + msg12426
2022-04-24 09:39:28adminsetmessages: + msg12425
2022-04-21 00:00:00admincreate