Title
Problems with counted_iterator/move_iterator::base() const &
Status
new
Section
[move.iterators][iterators.counted]
Submitter
Patrick Palka

Created on 2020-02-07.00:00:00 last changed 1 month ago

Messages

Date: 2020-02-10.19:13:13

Proposed resolution:

This wording is relative to N4849.

  1. Modify [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 [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 [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 [counted.iter.access] as indicated:

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

    -1- Effects: Equivalent to: return current;

Date: 2020-02-10.19:13:13

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

Date: 2020-02-07.00:00:00

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 [range.adaptors] could use the same treatment?

History
Date User Action Args
2020-02-10 19:13:13adminsetmessages: + msg11026
2020-02-08 15:24:46adminsetmessages: + msg11000
2020-02-07 00:00:00admincreate