This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.

### 3798. Rvalue reference and `iterator_category`

Section: 25.3.2.3 [iterator.traits] Status: WP Submitter: Jiang An Opened: 2022-10-22 Last modified: 2022-11-17

Priority: Not Prioritized

View all other issues in [iterator.traits].

View all issues with WP status.

Discussion:

Since C++11, a forward iterator may have an rvalue reference as its `reference` type. I think this is an intentional change made by N3066. However, several components added (or changed) in C++20/23 recognize an iterator as a Cpp17ForwardIterator (by using `forward_iterator_tag` or a stronger iterator category tag type as the `iterator_category` type) only if the `reference` type would be an lvalue reference type, which seems a regression.

[2022-11-01; Reflector poll]

Set status to Tentatively Ready after eight votes in favour during reflector poll.

[2022-11-12 Approved at November 2022 meeting in Kona. Status changed: Voting → WP.]

Proposed resolution:

This wording is relative to N4917.

1. Modify 25.3.2.3 [iterator.traits] as indicated:

   > -2- The definitions in this subclause make use of the following exposition-only concepts:

   > >     […]
   > >     template<class I>
   > >     concept cpp17-forward-iterator =
   > >       cpp17-input-iterator<I> && constructible_from<I> &&
   > >       is_lvalue_reference_v<iter_reference_t<I>> &&
   > >       same_as<remove_cvref_t<iter_reference_t<I>>,
   > >               typename indirectly_readable_traits<I>::value_type> &&
   > >       requires(I i) {
   > >         {  i++ } -> convertible_to<const I&>;
   > >         { *i++ } -> same_as<iter_reference_t<I>>;
   > >       };
   > >     […]

2. Modify 26.7.9.3 [range.transform.iterator] as indicated:

   > -2- The member typedef-name `iterator_category` is defined if and only if Base models `forward_range`. In that case, `iterator::iterator_category` is defined as follows: Let `C` denote the type `iterator_traits<iterator_t<Base>>::iterator_category`.

   > 1. (2.1) — If `is_lvalue_reference_v<invoke_result_t<maybe-const<Const, F>&, range_reference_t<Base>>>` is `true`, then

   >    1. (2.1.1) — if `C` models `derived_from<contiguous_iterator_tag>`, `iterator_category denotes random_access_iterator_tag`;

   >    2. (2.1.2) — otherwise, `iterator_category` denotes `C`.

   > 2. (2.2) — Otherwise, `iterator_category` denotes `input_iterator_tag`.

3. Modify 26.7.15.3 [range.join.with.iterator] as indicated:

   > -2- The member typedef-name `iterator_category` is defined if and only if `ref-is-glvalue` is `true`, and `Base` and `InnerBase` each model `forward_range`. In that case, `iterator::iterator_category` is defined as follows:

   > 1. (2.1) — […]

   > 2. (2.2) — If

   >    >     is_lvalue_reference_v<common_reference_t<iter_reference_t<InnerIter>,
   >    >                           iter_reference_t<PatternIter>>>

   >    is `false`, `iterator_category` denotes `input_iterator_tag`.

   > 3. (2.3) — […]

4. Modify 26.7.24.3 [range.zip.transform.iterator] as indicated:

   > -1- The member typedef-name `iterator::iterator_category` is defined if and only if `Base` models `forward_range`. In that case, `iterator::iterator_category` is defined as follows:

   > 1. (1.1) — If

   >    >     invoke_result_t<maybe-const<Const, F>&, range_reference_t<maybe-const<Const, Views>>...>

   >    is not an lvalue reference, `iterator_category` denotes `input_iterator_tag`.

   > 2. (1.2) — […]

5. Modify 26.7.26.3 [range.adjacent.transform.iterator] as indicated:

   > -1- The member typedef-name `iterator::iterator_category` is defined as follows:

   > 1. (1.1) — If `invoke_result_t<maybe-const<Const, F>&, REPEAT(range_reference_t<Base>, N)...>` is not an lvalue reference, `iterator_category` denotes `input_iterator_tag`.

   > 2. (1.2) — […]