Title
Types satisfying input_iterator but not equality_comparable look like C++17 output iterators
Status
resolved
Section
[iterator.traits]
Submitter
Eric Niebler

Created on 2019-09-10.00:00:00 last changed 35 months ago

Messages

Date: 2021-05-18.09:43:39

Proposed resolution:

This wording is relative to N4830.

  1. Modify [iterator.traits] as indicated:

    -3- The members of a specialization iterator_traits<I> generated from the iterator_traits primary template are computed as follows:

    1. (3.1) — If I has valid […]

    2. […]

    3. (3.3) — Otherwise, if I satisfies the exposition-only concept cpp17-iterator and either

      1. I::iterator_category is valid and denotes output_iterator_tag or a type publicly and unambiguously derived from output_iterator_tag, or

      2. there is no type I::iterator_category

      then iterator_traits<I> has the following publicly accessible members:

    4. […]

Date: 2021-05-18.00:00:00

[ 2021-05-18 Resolved by the adoption of P2259R1 at the February 2021 plenary. Status changed: New → Resolved. ]

Date: 2020-02-15.00:00:00

[ 2020-02-13, Prague; Priority reduced to 2 after LWG discussion ]

Date: 2019-11-07.08:57:59

[ 2019-11 Wednesday night Issue processing in Belfast ]

Much discussion along with 3289. CC to write rationale for NAD.

Date: 2019-10-12.00:00:00

[ 2019-10-12 Priority set to 1 after reflector discussion ]

Date: 2019-09-10.00:00:00

In C++20, if an iterator doesn't define all of the associated iterator types (value, category, reference, and difference), the primary std::iterator_traits template picks a category based on structural conformance to a set of implementation-defined concepts that capture the old iterator requirements tables. (See [iterator.traits].) In C++17, input iterators were required to be equality-comparable with themselves. In C++20 that is not the case, so such iterators must not be given intput_iterator_tag as a category. They don't, so that's all well and good.

However, [iterator.traits] concludes that, since such an iterator cannot be an input iterator, it must therefor be an output iterator, and it assigns it a category of std::output_iterator_tag. It does this even if there is a nested iterator_category typedef declaring the iterator to be input. (This will happen frequently as C++20 iterators don't require iterators to declare their reference type, for instance.) This will be extremely confusing to users who, understandably, will be at a loss to understand why the legacy STL algorithms think their iterator is an output iterator when they have clearly stated that the iterator is input!

The fix is to tweak the specification such that the output category is assigned to an iterator only (a) if it declares its category to be output, or (b) it doesn't specify a category at all. The result, for the user, is that their iterator simply won't look like a C++17 iterator at all, because it isn't!

Suggested priority: P1. We can't make this change after C++20 because it would be an observable change.

This fix has been implemented in range-v3.

History
Date User Action Args
2021-05-18 09:43:39adminsetmessages: + msg11811
2021-05-18 09:43:39adminsetstatus: new -> resolved
2020-02-13 18:18:00adminsetmessages: + msg11075
2019-11-07 08:57:59adminsetmessages: + msg10790
2019-10-12 11:38:05adminsetmessages: + msg10696
2019-09-16 17:54:12adminsetmessages: + msg10637
2019-09-10 00:00:00admincreate