3533. Make base() const & consistent across iterator wrappers that supports input_iterators

Section: 25.7.8.3 [range.filter.iterator], 25.7.9.3 [range.transform.iterator], 25.7.23.3 [range.elements.iterator] Status: C++23 Submitter: Tomasz Kamiński Opened: 2021-03-14 Last modified: 2023-11-22

Priority: Not Prioritized

View all issues with C++23 status.

Discussion:

The resolution of LWG issue 3391 changed the base() function for the counted_iterator/move_iterator to return const &, because the previous specification prevented non-mutating uses of the base iterator (comparing against sentinel) and made take_view unimplementable. However, this change was not applied for all other iterators wrappers, that may wrap move-only input iterators. As consequence, we end-up with inconsistency where a user can perform the following operations on some adapters, but not on others (e. g. take_view uses counted_iterator so it supports them).

  1. read the original value of the base iterator, by calling operator*

  2. find position of an element in the underlying iterator, when sentinel is sized by calling operator- (e.g. all input iterators wrapped into counted_iterator).

To fix above, the proposed wording below proposes to modify the signature of iterator::base() const & member function for all iterators adapters that support input iterator. These include:

Note: common_iterator does not expose the base() function (because it can either point to iterator or sentinel), so changes to above are not proposed. However, both (A) and (B) use cases are supported.

[2021-04-20; Reflector poll]

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

[2021-06-07 Approved at June 2021 virtual plenary. Status changed: Voting → WP.]

Proposed resolution:

This wording is relative to N4878.

If P2210 would become accepted, the corresponding subclause [range.lazy.split.inner] (?) for lazy_split_view::inner-iterator would require a similar change.

  1. Modify 25.7.8.3 [range.filter.iterator] as indicated:

    […]
    constexpr const iterator_t<V>& base() const &
      requires copyable<iterator_t<V>>;
    […]
    
    […]
    constexpr const iterator_t<V>& base() const &
      requires copyable<iterator_t<V>>;
    

    -5- Effects: Equivalent to: return current_;

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

    […]
    constexpr const iterator_t<Base>& base() const &
      requires copyable<iterator_t<Base>>;
    […]
    
    […]
    constexpr const iterator_t<Base>& base() const &
      requires copyable<iterator_t<Base>>;
    

    -5- Effects: Equivalent to: return current_;

  3. Modify 25.7.23.3 [range.elements.iterator] as indicated:

    […]
    constexpr const iterator_t<Base>& base() const &
      requires copyable<iterator_t<Base>>;
    […]
    
    […]
    constexpr const iterator_t<Base>& base() const &
      requires copyable<iterator_t<Base>>;
    

    -3- Effects: Equivalent to: return current_;