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

### 3609. `std::ranges::iota_view<int, long>` has non-subtractable `iterator` and `sentinel` types

Section: 26.6.4.4 [range.iota.sentinel] Status: New Submitter: Jiang An Opened: 2021-09-25 Last modified: 2021-10-14

Priority: 3

View all issues with New status.

Discussion:

Currently `std::ranges::iota_view<int, long>` uses its special `sentinel` type, as its `W` and `Bound` are different types and `Bound` is not `std::unreachable_sentinel_t`. However, as `W` (`int`) is not an iterator type, the iterator and sentinel types don't satisfy `std::sized_sentinel_for`, and thus not subtractable.

IMO we should handle `operator-` overloads for `iota_view::iterator` and `iota_view::sentinel` like `iota_view::size` and `operator-` for `iota_view::iterator`.

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

[Tim Song commented:]

We might be able to simplify the `(y_value > x.value_)` conditional since we know that we are working with an iterator and its sentinel.

Proposed resolution:

This wording is relative to N4892.

1. Modify 26.6.4.4 [range.iota.sentinel] as indicated:

   > >     namespace std::ranges {
   > >       template<weakly_incrementable W, semiregular Bound>
   > >         requires weakly-equality-comparable-with<W, Bound> && copyable<W>
   > >       struct iota_view<W, Bound>::sentinel {
   > >       private:
   > >         Bound bound_ = Bound(); // exposition only
   > >       public:
   > >         sentinel() = default;
   > >         constexpr explicit sentinel(Bound bound);

   > >         friend constexpr bool operator==(const iterator& x, const sentinel& y);

   > >         friend constexpr iter_difference_t<W>IOTA-DIFF-T(W) operator-(const iterator& x, const sentinel& y)
   > >           requires (is-integer-like<W> && is-integer-like<Bound>) || sized_sentinel_for<Bound, W>;

   > >         friend constexpr iter_difference_t<W>IOTA-DIFF-T(W) operator-(const sentinel& x, const iterator& y)
   > >           requires (is-integer-like<W> && is-integer-like<Bound>) || sized_sentinel_for<Bound, W>;
   > >       };
   > >     }

   > […]

   >     friend constexpr iter_difference_t<W>IOTA-DIFF-T(W) operator-(const iterator& x, const sentinel& y)
   >       requires (is-integer-like<W> && is-integer-like<Bound>) || sized_sentinel_for<Bound, W>;

   > > -3- Effects: Equivalent to: `return x.value_ - y.bound_;`

   > > >     using D = IOTA-DIFF-T(W);
   > > >     if constexpr (is-integer-like<W>) {
   > > >       auto y_value = W(y.bound_);
   > > >       if constexpr (is-signed-integer-like<W>) {
   > > >         return D(D(x.value_) - D(y_value));
   > > >       } else {
   > > >         return (y_value > x.value_)
   > > >           ? D(-D(y_value - x.value_))
   > > >           : D(x.value_ - y_value);
   > > >       }
   > > >     } else {
   > > >       return x.value_ - y.bound_;
   > > >     }

   >     friend constexpr iter_difference_t<W>IOTA-DIFF-T(W) operator-(const sentinel& x, const iterator& y)
   >       requires (is-integer-like<W> && is-integer-like<Bound>) || sized_sentinel_for<Bound, W>;

   > > -4- Effects: Equivalent to: `return -(y - x);`