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.

### 3749. `common_iterator` should handle integer-class difference types

Section: 25.5.5 [iterators.common] Status: New Submitter: Hewill Kang Opened: 2022-08-01 Last modified: 2022-08-23

Priority: 2

View all issues with New status.

Discussion:

The partial specialization of `iterator_traits` for `common_iterator` is defined in 25.5.5.1 [common.iterator] as

    template<input_iterator I, class S>
    struct iterator_traits<common_iterator<I, S>> {
      using iterator_concept = see below;
      using iterator_category = see below;
      using value_type = iter_value_t<I>;
      using difference_type = iter_difference_t<I>;
      using pointer = see below;
      using reference = iter_reference_t<I>;
    };

where `difference_type` is defined as `iter_difference_t<I>` and `iterator_category` is defined as at least `input_iterator_tag`. However, when `difference_type` is an integer-class type, `common_iterator` does not satisfy Cpp17InputIterator, which makes `iterator_category` incorrectly defined as `input_iterator_tag`.

Since the main purpose of `common_iterator` is to be compatible with the legacy iterator system, which is reflected in its efforts to try to provide the operations required by C++17 iterators even if the underlying iterator does not support it. We should handle this case of difference type incompatibility as well.

The proposed solution is to provide a C++17 conforming difference type by clamping the integer-class type to `ptrdiff_t`.

Daniel:

> The second part of this issue provides an alternative resolution for the first part of LWG 3748 and solves the casting problem mentioned in LWG 3748 as well.

[2022-08-23; Reflector poll]

Set priority to 2 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."

"I'm not yet convinced that we need to outright reject such uses, but I'm pretty sure that we shouldn't mess with the difference type and that the PR is in the wrong direction."

Proposed resolution:

This wording is relative to N4910.

1. Modify 25.5.5.1 [common.iterator] as indicated:

   > [Drafting note: `common_iterator` requires iterator type `I` must model `input_or_output_iterator` which ensures that `iter_difference_t<I>` is a signed-integer-like type. The modification of `common_iterator::operator-` is to ensure that the pair of `common_iterator<I, S>` models `sized_sentinel_for` when `sized_sentinel_for<I, S>` is modeled for iterator type `I` with an integer-class difference type and its sentinel type `S`.]

   >     namespace std {
   >       template<class D>
   >         requires is-signed-integer-like<D>
   >       using make-cpp17-diff-t = conditional_t<signed_integral<D>, D, ptrdiff_t>;  // exposition only

   >       template<input_or_output_iterator I, sentinel_for<I> S>
   >         requires (!same_as<I, S> && copyable<I>)
   >       class common_iterator {
   >       public:
   >         […]
   >         template<sized_sentinel_for<I> I2, sized_sentinel_for<I> S2>
   >           requires sized_sentinel_for<S, I2>
   >         friend constexpr make-cpp17-diff-t<iter_difference_t<I2>> operator-(
   >           const common_iterator& x, const common_iterator<I2, S2>& y);
   >         […]
   >       };

   >       template<class I, class S>
   >       struct incrementable_traits<common_iterator<I, S>> {
   >         using difference_type = make-cpp17-diff-t<iter_difference_t<I>>;
   >       };

   >       template<input_iterator I, class S>
   >       struct iterator_traits<common_iterator<I, S>> {
   >         using iterator_concept = see below;
   >         using iterator_category = see below;
   >         using value_type = iter_value_t<I>;
   >         using difference_type = make-cpp17-diff-t<iter_difference_t<I>>;
   >         using pointer = see below;
   >         using reference = iter_reference_t<I>;
   >       };
   >     }

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

   > [Drafting note: If this issue is voted in at the same time as LWG 3748, the editor is kindly informed that the changes indicated below supersede those of the before mentioned issues first part.]

   >     template<sized_sentinel_for<I> I2, sized_sentinel_for<I> S2>
   >       requires sized_sentinel_for<S, I2>
   >     friend constexpr make-cpp17-diff-t<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<make-cpp17-diff-t<iter_difference_t<I2>>>(``get<i>(x.v_) - get<j>(y.v_)``)`, where `i` is `x.v_.index()` and `j` is `y.v_.index()`.