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 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."
Previous resolution [SUPERSEDED]:
This wording is relative to N4910.
Modify 24.5.5.1 [common.iterator] as indicated:
[Drafting note:
common_iterator
requires iterator typeI
must modelinput_or_output_iterator
which 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_for
whensized_sentinel_for<I, S>
is modeled for iterator typeI
with 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, 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
.0
ifi
andj
are each1
, and otherwisestatic_cast<make-cpp17-diff-t<iter_difference_t<I2>>>(
get<i>(x.v_) - get<j>(y.v_)
)
, wherei
isx.v_.index()
andj
isy.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_category
of the specialization ofiterator_traits
forcommon_iterator<I, S>
is defined if and only ifiter_difference_t<I>
is an integral type. In that case,iterator_category
denotesforward_iterator_tag
if the qualified-iditerator_traits<I>::iterator_category
is 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_traits
forcommon_iterator<I, S>
are defined as follows.:
(1.1) —
iterator_concept
denotesforward_iterator_tag
ifI
modelsforward_iterator
; otherwise it denotesinput_iterator_tag
.
(1.2) —iterator_category
denotesforward_iterator_tag
if the qualified-iditerator_traits<I>::iterator_category
is valid and denotes a type that modelsderived_from<forward_iterator_tag>
; otherwise it denotesinput_iterator_tag
.(1.3) — Let
a
denote an lvalue of typeconst common_iterator<I, S>
. If the expressiona.operator->()
is well-formed, thenpointer
denotesdecltype(a.operator->())
. Otherwise,pointer
denotesvoid
.