3602. reverse_iterator's converting assignment is overconstrained

Section: 24.5.1.4 [reverse.iter.cons], 24.5.4.4 [move.iter.cons] Status: New Submitter: Hewill Kang Opened: 2021-09-26 Last modified: 2021-10-14

Priority: 3

View all other issues in [reverse.iter.cons].

View all issues with New status.

Discussion:

In order to remove the incorrect bi-convertibility of reverse_iterator<int*> and reverse_iterator<const int*>, LWG 3435 adds two constraints to reverse_iterator's converting assignment, namely convertible_to<const U&, Iterator> and assignable_from<Iterator&, const U&>, but since this function only assigns u.current to current, there is no need to require convertible_to<const U&, Iterator> — the latter is sufficient.

We should remove this constraint and be consistent with the move_sentinel and counted_iterator' converting assignment.

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

[Tim Song commented:]

This was intentional, but I think we missed the fact that counted_iterator did something else already. These should probably be made consistent one way or another.

[Tomasz KamiƄski commented]

The move_iterator/reverse_iterator were present before C++20, and this change restores their compatibility with C++17 code, where only assignment was required. They are materially different from adapters introduced with C++20, and I believe we should put more weight into backward compatibility than consistency with newer iterator wrappers.

Proposed resolution:

This wording is relative to N4892.

  1. Modify 24.5.1.4 [reverse.iter.cons] as indicated:

    template<class U>
      constexpr reverse_iterator&
        operator=(const reverse_iterator<U>& u);
    

    -5- Constraints: is_same_v<U, Iterator> is false, const U& models convertible_to<Iterator>, and assignable_from<Iterator&, const U&> is modeled.

    -6- Effects: Assigns u.current to current.

    -7- Returns: *this.

  2. Modify 24.5.4.4 [move.iter.cons] as indicated:

    [Drafting note: As drive-by fix a missing "Returns: *this" has been added as well.]

    template<class U> constexpr move_iterator& operator=(const move_iterator<U>& u);
    

    -5- Constraints: is_same_v<U, Iterator> is false, const U& models convertible_to<Iterator>, and assignable_from<Iterator&, const U&> is modeled.

    -6- Effects: Assigns u.current to current.

    -?- Returns: *this.