This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++20 status.

### 3388. `view` iterator types have ill-formed `<=>` operators

Section: 26.6.4.3 [range.iota.iterator], 26.7.9.3 [range.transform.iterator], 26.7.22.3 [range.elements.iterator] Status: C++20 Submitter: Jonathan Wakely Opened: 2020-02-07 Last modified: 2021-02-25

Priority: 0

View all other issues in [range.iota.iterator].

View all issues with C++20 status.

Discussion:

26.6.4.3 [range.iota.iterator] and 26.7.9.3 [range.transform.iterator] and 26.7.22.3 [range.elements.iterator] all declare `operator<=>` similar to this:

>     friend constexpr compare_three_way_result_t<W> operator<=>(
>         const iterator& x, const iterator& y)
>       requires totally_ordered<W> && three_way_comparable<W>;

Similar to issue 3347 and issue 3387, this is ill-formed if `three_way_comparable<W>` is not satisfied, because `compare_three_way_result_t<W>` is invalid. This declaration is instantiated when the enclosing iterator type is instantiated, making any use of `iota_view<W, B>::iterator` ill-formed when `three_way_comparable<W>` is not satisfied.

We can either add an exposition-only `safe-compare-three-way-result-t` alias that denotes `void` or `std::nonesuch` for spaceship-less types, so the declaration is valid (and then disabled by the constraints), or simply make them return `auto`.

[2020-02 Prioritized as IMMEDIATE Monday morning in Prague]

Proposed resolution:

This wording is relative to N4849.

1. Modify 26.6.4.3 [range.iota.iterator] as indicated:

   > >     namespace std::ranges {
   > >       template<class W, class Bound>
   > >       struct iota_view<W, Bound>::iterator {
   > >         […]
   > >         friend constexpr compare_three_way_result_t<W>auto operator<=>(
   > >             const iterator& x, const iterator& y)
   > >           requires totally_ordered<W> && three_way_comparable<W>;
   > >         […]
   > >       };
   > >       […]
   > >     }

   > > […]

   > >     friend constexpr compare_three_way_result_t<W>auto
   > >       operator<=>(const iterator& x, const iterator& y)
   > >         requires totally_ordered<W> && three_way_comparable<W>;

   > > > -19- Effects: Equivalent to: `return x.value_ <=> y.value_;`

2. Modify 26.7.9.3 [range.transform.iterator] as indicated:

   > >     namespace std::ranges {
   > >       template<class V, class F>
   > >       template<bool Const>
   > >       class transform_view<V, F>::iterator {
   > >         […]
   > >         friend constexpr compare_three_way_result_t<iterator_t<Base>>auto
   > >           operator<=>(const iterator& x, const iterator& y)
   > >             requires random_access_range<Base> && three_way_comparable<iterator_t<Base>>;
   > >         […]
   > >       };
   > >       […]
   > >     }

   > > […]

   > >     friend constexpr compare_three_way_result_t<iterator_t<Base>>auto
   > >       operator<=>(const iterator& x, const iterator& y)
   > >         requires random_access_range<Base> && three_way_comparable<iterator_t<Base>>;

   > > > -19- Effects: Equivalent to: `return x.current_ <=> y.current_;`

3. Modify 26.7.22.3 [range.elements.iterator] as indicated:

   > >     namespace std::ranges {
   > >       template<class V, size_t N>
   > >       template<bool Const>
   > >       class elements_view<V, N>::iterator {
   > >         […]
   > >         friend constexpr compare_three_way_result_t<iterator_t<base-t>>auto
   > >           operator<=>(const iterator& x, const iterator& y)
   > >             requires random_access_range<base-t> && three_way_comparable<iterator_t<base-t>>;
   > >         […]
   > >       };
   > >       […]
   > >     }

   > > […]

   > >     friend constexpr compare_three_way_result_t<iterator_t<base-t>>auto
   > >       operator<=>(const iterator& x, const iterator& y)
   > >         requires random_access_range<base-t> && three_way_comparable<iterator_t<base-t>>;

   > > > -18- Effects: Equivalent to: `return x.current_ <=> y.current_;`