This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Resolved status.
Section: 24.3.2.3 [iterator.traits], 24.5.5.2 [common.iter.types] Status: Resolved Submitter: Eric Niebler Opened: 2019-09-11 Last modified: 2021-05-18
Priority: 2
View all other issues in [iterator.traits].
View all issues with Resolved status.
Discussion:
The way to non-intrusively say that a type doesn't satisfy the C++17 iterator requirements is to
specialize std::iterator_traits
and not provide the nested typedefs. However, if a user
were to do that, she would also be saying that the type is not a C++20 iterator. That is
because readable
and weakly_incrementable
are specified in terms of
iter_value_t<I>
and iter_difference_t<I>
. Those aliases check to
see if std::iterator_traits<I>
has been specialized (answer: yes), and if so
resolve to std::iterator_traits<I>::value_type
and
std::iterator_traits<I>::difference_type
respectively.
std::iterator_traits
and specify all the nested typedefs except
::iterator_category
. That's a bit weird and may throw off code that is expecting all the
typedefs to be there, or none of them, so instead we can suggest users to set the iterator_category
typedef to denote output_iterator_tag
, which is a harmless lie; generic C++17 code will get
the message: this iterator is not a c++17 input iterator, which is the salient bit.
We then must fix up all the places in the Ranges clause that make faulty assumptions about an
iterator's iterator_category
typedef (as distinct from the iterator concept that it models).
[2019-10-19 Issue Prioritization]
Priority to 1 after reflector discussion.
[2019-11 Wednesday night Issue processing in Belfast]
Much discussion; no consensus that this is a good approach. Need to coordinate between this and 3283(i)
Previous resolution [SUPERSEDED]:This wording is relative to N4830.
Modify 24.3.2.3 [iterator.traits] as indicated:
-4- Explicit or partial specializations of
iterator_traits
may have a member typeiterator_concept
that is used to indicate conformance to the iterator concepts (24.3.4 [iterator.concepts]). [Example: To indicate conformance to theinput_iterator
concept but a lack of conformance to the Cpp17InputIterator requirements (24.3.5.3 [input.iterators]), aniterator_traits
specialization might haveiterator_concept
denoteinput_iterator_tag
anditerator_category
denoteoutput_iterator_tag
. — end example]Modify 24.5.5.2 [common.iter.types] as indicated:
-1- The 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
ifiterator_traits<I>::iterator_category
modelsderived_from<forward_iterator_tag>
; otherwise it denotes.
input_iterator_tagiterator_traits<I>::iterator_category(1.3) — If the expression
a.operator->()
is well-formed, wherea
is an lvalue of typeconst common_iterator<I, S>
, thenpointer
denotes the type of that expression. Otherwise, pointer denotesvoid
.Modify 25.7.8.3 [range.filter.iterator] as indicated:
-3-
iterator::iterator_category
is defined as follows:
(3.1) — Let
C
denote the typeiterator_traits<iterator_t<V>>::iterator_category
.(3.2) — If
C
modelsderived_from<bidirectional_iterator_tag>
, theniterator_category
denotesbidirectional_iterator_tag
.
(3.3) — Otherwise, ifC
modelsderived_from<forward_iterator_tag>
, theniterator_category
denotesforward_iterator_tag
.(3.4) — Otherwise,
iterator_category
denotes.
input_iterator_tagCModify 25.7.14.3 [range.join.iterator] as indicated:
-3-
iterator::iterator_category
is defined as follows:
(3.1) — Let
OUTERC
denoteiterator_traits<iterator_t<Base>>::iterator_category
, and letINNERC
denoteiterator_traits<iterator_t<range_reference_t<Base>>>::iterator_category
.(3.?) — If
OUTERC
does not modelderived_from<input_iterator_tag>
,iterator_category
denotesOUTERC
.(3.?) — Otherwise, if
INNERC
does not modelderived_from<input_iterator_tag>
,iterator_category
denotesINNERC
.(3.2) — Otherwise, i
Ifref_is_glvalue
istrue
,
(3.2.1) — If
OUTERC
andINNERC
each modelderived_from<bidirectional_iterator_tag>
,iterator_category
denotesbidirectional_iterator_tag
.(3.2.2) — Otherwise, if
OUTERC
andINNERC
each modelderived_from<forward_iterator_tag>
,iterator_category
denotesforward_iterator_tag
.(3.3) — Otherwise,
iterator_category
denotesinput_iterator_tag
.Modify [range.split.outer] as indicated:
namespace std::ranges { template<class V, class Pattern> template<bool Const> struct split_view<V, Pattern>::outer_iterator { private: […] public: using iterator_concept = conditional_t<forward_range<Base>, forward_iterator_tag, input_iterator_tag>; using iterator_category = see belowinput_iterator_tag; […] }; […] }-?- The typedef-name
-1- Many of the following specifications refer to the notional memberiterator_category
denotesinput_iterator_tag
ifiterator_traits<iterator_t<Base>>::iterator_category
modelsderived_from<input_iterator_tag>
, anditerator_traits<iterator_t<Base>>::iterator_category
otherwise.current
ofouter_iterator
.current
is equivalent tocurrent_
ifV
modelsforward_range
, andparent_->current_
otherwise.Modify [range.split.inner] as indicated:
-1- The typedef-name
iterator_category
denotesforward_iterator_tag
ifiterator_traits<iterator_t<Base>>::iterator_category
modelsderived_from<forward_iterator_tag>
, andotherwise.
input_iterator_tagiterator_traits<iterator_t<Base>>::iterator_category
[2020-02-10, Prague]
The issue is out of sync with the current working draft, Daniel provides a synchronized merge.
[2020-02-13, Prague; Priority reduced to 2 after LWG discussion]
[2021-05-18 Resolved by the adoption of P2259R1 at the February 2021 plenary. Status changed: New → Resolved.]
Proposed resolution:
This wording is relative to N4849.
Modify 24.3.2.3 [iterator.traits] as indicated:
-4- Explicit or partial specializations of
iterator_traits
may have a member typeiterator_concept
that is used to indicate conformance to the iterator concepts (24.3.4 [iterator.concepts]). [Example: To indicate conformance to theinput_iterator
concept but a lack of conformance to the Cpp17InputIterator requirements (24.3.5.3 [input.iterators]), aniterator_traits
specialization might haveiterator_concept
denoteinput_iterator_tag
anditerator_category
denoteoutput_iterator_tag
. — end example]
Modify 24.5.5.2 [common.iter.types] as indicated:
-1- The 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
ifiterator_traits<I>::iterator_category
modelsderived_from<forward_iterator_tag>
; otherwise it denotes.
input_iterator_tagiterator_traits<I>::iterator_category(1.3) — If the expression
a.operator->()
is well-formed, wherea
is an lvalue of typeconst common_iterator<I, S>
, thenpointer
denotes the type of that expression. Otherwise, pointer denotesvoid
.
Modify 25.7.8.3 [range.filter.iterator] as indicated:
-3-
iterator::iterator_category
is defined as follows:
(3.1) — Let
C
denote the typeiterator_traits<iterator_t<V>>::iterator_category
.(3.2) — If
C
modelsderived_from<bidirectional_iterator_tag>
, theniterator_category
denotesbidirectional_iterator_tag
.
(3.3) — Otherwise, ifC
modelsderived_from<forward_iterator_tag>
, theniterator_category
denotesforward_iterator_tag
.(3.4) — Otherwise,
iterator_category
denotesC
.
Modify 25.7.14.3 [range.join.iterator] as indicated:
-2-
iterator::iterator_category
is defined as follows:
(2.1) — Let
OUTERC
denoteiterator_traits<iterator_t<Base>>::iterator_category
, and letINNERC
denoteiterator_traits<iterator_t<range_reference_t<Base>>>::iterator_category
.(2.?) — If
OUTERC
does not modelderived_from<input_iterator_tag>
,iterator_category
denotesOUTERC
.(2.?) — Otherwise, if
INNERC
does not modelderived_from<input_iterator_tag>
,iterator_category
denotesINNERC
.(2.2) — Otherwise, i
Ifref-is-glvalue
istrue
andOUTERC
andINNERC
each modelderived_from<bidirectional_iterator_tag>
,iterator_category
denotesbidirectional_iterator_tag
.(2.3) — Otherwise, if
ref-is-glvalue
istrue
andOUTERC
andINNERC
each modelderived_from<forward_iterator_tag>
,iterator_category
denotesforward_iterator_tag
.(2.4) — Otherwise, if
OUTERC
andINNERC
each modelderived_from<input_iterator_tag>
,iterator_category
denotesinput_iterator_tag
.(2.5) — Otherwise,
iterator_category
denotesoutput_iterator_tag
.
Modify [range.split.outer] as indicated:
[Drafting note: The previous wording change has been adjusted to follow the pattern used in [range.split.inner] p1.]
namespace std::ranges { template<class V, class Pattern> template<bool Const> struct split_view<V, Pattern>::outer_iterator { private: […] public: using iterator_concept = conditional_t<forward_range<Base>, forward_iterator_tag, input_iterator_tag>; using iterator_category = see belowinput_iterator_tag; […] }; […] }-?- The typedef-name
iterator_category
denotes:
(?.?) —
input_iterator_tag
ifiterator_traits<iterator_t<Base>>::iterator_category
modelsderived_from<input_iterator_tag>
;(?.?) — otherwise,
iterator_traits<iterator_t<Base>>::iterator_category
.-1- Many of the following specifications refer to the notional member
current
ofouter-iterator
.current
is equivalent tocurrent_
ifV
modelsforward_range
, andparent_->current_
otherwise.