This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
common_iterator should handle integer-class difference typesSection: 24.5.5 [iterators.common] Status: WP Submitter: Hewill Kang Opened: 2022-08-01 Last modified: 2023-11-22
Priority: 2
View all issues with WP status.
Discussion:
The partial specialization of iterator_traits for common_iterator is defined in
24.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.
ptrdiff_t.
Daniel:
The second part of this issue provides an alternative resolution for the first part of LWG 3748(i) and solves the casting problem mentioned in LWG 3748(i) 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."
Previous resolution [SUPERSEDED]:
This wording is relative to N4910.
Modify 24.5.5.1 [common.iterator] as indicated:
[Drafting note:
common_iteratorrequires iterator typeImust modelinput_or_output_iteratorwhich ensures thatiter_difference_t<I>is a signed-integer-like type. The modification ofcommon_iterator::operator-is to ensure that the pair ofcommon_iterator<I, S>modelssized_sentinel_forwhensized_sentinel_for<I, S>is modeled for iterator typeIwith an integer-class difference type and its sentinel typeS.]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>; }; }Modify 24.5.5.6 [common.iter.cmp] as indicated:
[Drafting note: If this issue is voted in at the same time as LWG 3748(i), 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:
-6- Returns:x.v_.valueless_by_exception()andy.v_.valueless_by_exception()are eachfalse.0ifiandjare each1, and otherwisestatic_cast<make-cpp17-diff-t<iter_difference_t<I2>>>(get<i>(x.v_) - get<j>(y.v_)), whereiisx.v_.index()andjisy.v_.index().
[2023-06-13; Varna; Tomasz provides wording]
[2023-06-14 Varna; Move to Ready]
[2023-11-11 Approved at November 2023 meeting in Kona. Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4950.
Modify 24.5.5.1 [common.iterator] as indicated:
namespace std {
[…]
template<input_iterator I, class S>
struct iterator_traits<common_iterator<I, S>> {
using iterator_concept = see below;
using iterator_category = see below; // not always present
using value_type = iter_value_t<I>;
using difference_type = iter_difference_t<I>;
using pointer = see below;
using reference = iter_reference_t<I>;
};
}
Modify 24.5.5.2 [common.iter.types] as indicated:
-?- The nested typedef-name
iterator_categoryof the specialization ofiterator_traitsforcommon_iterator<I, S>is defined if and only ifiter_difference_t<I>is an integral type. In that case,iterator_categorydenotesforward_iterator_tagif the qualified-iditerator_traits<I>::iterator_categoryis valid and denotes a type that modelsderived_from<forward_iterator_tag>; otherwise it denotesinput_iterator_tag.-1- The remaining nested typedef-names of the specialization of
iterator_traitsforcommon_iterator<I, S>are defined as follows.:
(1.1) —
iterator_conceptdenotesforward_iterator_tagifImodelsforward_iterator; otherwise it denotesinput_iterator_tag.
(1.2) —iterator_categorydenotesforward_iterator_tagif the qualified-iditerator_traits<I>::iterator_categoryis valid and denotes a type that modelsderived_from<forward_iterator_tag>; otherwise it denotesinput_iterator_tag.(1.3) — Let
adenote an lvalue of typeconst common_iterator<I, S>. If the expressiona.operator->()is well-formed, thenpointerdenotesdecltype(a.operator->()). Otherwise,pointerdenotesvoid.