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.

### 3391. Problems with `counted_iterator/move_iterator::base() const &`

Section: 23.5.3 [move.iterators], 23.5.6 [iterators.counted] Status: WP Submitter: Patrick Palka Opened: 2020-02-07 Last modified: 2021-02-26

Priority: 2

View all other issues in [move.iterators].

View all issues with WP status.

Discussion:

It is not possible to use the `const &` overloads of `counted_iterator::base()` or `move_iterator::base()` to get at an underlying move-only iterator in order to compare it against a sentinel.

More concretely, assuming issue LWG 3389 is fixed, this means that

>     auto v = r | views::take(5);
>     ranges::begin(v) == ranges::end(v);

is invalid when `r` is a `view` whose `begin()` is a move-only input iterator. The code is invalid because `ranges::take_view::sentinel::operator==()` must call `counted_iterator::base()` to compare the underlying iterator against its sentinel, and therefore this `operator==()` requires that the underlying iterator is `copy_constructible`.

Suggested resolution:

Make these `const & base()` overloads return the underlying iterator by `const` reference. Remove the `copy_constructible` constraint on these overloads. Perhaps the `base()` overloads for the iterator wrappers in 24.7 [range.adaptors] could use the same treatment?

[2020-02 Prioritized as P2 Monday morning in Prague]

[2021-01-28; Reflector poll]

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

[2021-02-26 Approved at February 2021 virtual plenary. Status changed: Tentatively Ready → WP.]

Proposed resolution:

This wording is relative to N4849.

1. Modify 23.5.3.2 [move.iterator], class template `move_iterator` synopsis, as indicated:

   >     namespace std {
   >       template<class Iterator>
   >       class move_iterator {
   >       public:
   >         using iterator_type = Iterator;
   >         […]
   >         constexpr const iterator_type& base() const &;
   >         constexpr iterator_type base() &&;
   >         […]
   >       };
   >     }

2. Modify 23.5.3.5 [move.iter.op.conv] as indicated:

   >     constexpr const Iterator& base() const &;

   > > -1- Constraints: `Iterator` satisfies `copy_constructible`.

   > > -2- Preconditions: `Iterator` models `copy_constructible`.

   > > -3- Returns: `current`.

3. Modify 23.5.6.1 [counted.iterator], class template `counted_iterator` synopsis, as indicated:

   >     namespace std {
   >       template<input_or_output_iterator I>
   >       class counted_iterator {
   >       public:
   >         using iterator_type = I;
   >         […]
   >         constexpr const I& base() const & requires copy_constructible<I>;
   >         constexpr I base() &&;
   >         […]
   >       };
   >     }

4. Modify 23.5.6.3 [counted.iter.access] as indicated:

   >     constexpr const I& base() const & requires copy_constructible<I>;

   > > -1- Effects: Equivalent to: `return current;`