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.

### 3748. `common_iterator` and `counted_iterator`' `operator-` are missing cast to return type

Section: 25.5.5.6 [common.iter.cmp], 25.5.7.5 [counted.iter.nav] Status: New Submitter: Hewill Kang Opened: 2022-08-01 Last modified: 2022-08-23

Priority: 3

View all issues with New status.

Discussion:

Both `common_iterator` and `counted_iterator` explicitly specify that the return type of their `operator-` is `iter_difference_t<I2>`, however, given that the calculated type may be `iter_difference_t<I>`, we should do an explicit conversion here since the latter is not necessarily implicitly convertible to the former:

>     #include <ranges>

>     struct Y;

>     struct X {
>       X(Y);
>       using difference_type =
>     #ifdef __GNUC__
>       std::ranges::__detail::__max_diff_type;
>     #elif defined(_MSC_VER)
>       std::_Signed128;
>     #endif
>       int& operator*() const;
>       X& operator++();
>       void operator++(int);
>     };

>     struct Y {
>       using difference_type = std::ptrdiff_t;
>       int& operator*() const;
>       Y& operator++();
>       void operator++(int);
>     };

>     int main() {
>       std::counted_iterator<Y> y;
>       return std::counted_iterator<X>(y) - y; // hard error in stdlibc++ and MSVC-STL
>     }

Daniel:

> This issue shouldn't we voted until a decision for LWG 3749 has been made, because the first part of it overlaps with LWG 3749's second part.

[2022-08-23; Reflector poll]

Set priority to 3 after reflector poll.

"I think `common_iterator` should reject iterators with integer-class difference types since it can't possibly achieve the design intent of adapting them to Cpp17Iterators, so this issue should only affect `counted_iterator`."

"If the difference types of `I` and `I2` are different then the `operator-` can't be used to model `sized_sentinel_for`, since `i - i2` and `i2 - i` would have different types. Providing `operator-` under such circumstances seems to be of dubious value."

Proposed resolution:

This wording is relative to N4910.

1. Modify 25.5.5.6 [common.iter.cmp] as indicated:

   >     template<sized_sentinel_for<I> I2, sized_sentinel_for<I> S2>
   >       requires sized_sentinel_for<S, I2>
   >     friend constexpr iter_difference_t<I2> operator-(
   >       const common_iterator& x, const common_iterator<I2, S2>& y);

   > > -5- Preconditions: `x.v_.valueless_by_exception()` and `y.v_.valueless_by_exception()` are each `false`.

   > > -6- Returns: `0` if `i` and `j` are each `1`, and otherwise `static_cast<iter_difference_t<I2>>(``get<i>(x.v_) - get<j>(y.v_)``)`, where `i` is `x.v_.index()` and `j` is `y.v_.index()`.

2. Modify 25.5.7.5 [counted.iter.nav] as indicated:

   >     template<common_with<I> I2>
   >       friend constexpr iter_difference_t<I2> operator-(
   >         const counted_iterator& x, const counted_iterator<I2>& y);

   > > -13- Preconditions: `x` and `y` refer to elements of the same sequence (25.5.7.1 [counted.iterator]).

   > > -14- Effects: Equivalent to: `return static_cast<iter_difference_t<I2>>(y.length - x.length);`