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.

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

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

Priority: 2

View all other issues in [iterator.traits].

View all issues with Resolved status.

Discussion:

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