3283. Types satisfying input_iterator but not equality_comparable look like C++17 output iterators

Section: [iterator.traits] Status: Resolved Submitter: Eric Niebler Opened: 2019-09-10 Last modified: 2021-05-18 09:43:39 UTC

Priority: 2

View all other issues in [iterator.traits].

View all issues with Resolved status.


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.

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

[2019-11 Wednesday night Issue processing in Belfast]

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

[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 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. […]