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.

### 3435. `three_way_comparable_with<reverse_iterator<int*>, reverse_iterator<const int*>>`

Section: 23.5.3.4 [move.iter.cons], 23.5.1.4 [reverse.iter.cons] Status: WP Submitter: Casey Carter Opened: 2020-04-26 Last modified: 2020-11-09

Priority: 2

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

View all issues with WP status.

Discussion:

Despite that `reverse_iterator<int*>` and `reverse_iterator<const int*>` are comparable with `<=>`, `three_way_comparable_with<reverse_iterator<int*>, reverse_iterator<const int*>>` is `false`. This unfortunate state of affairs results from the absence of constraints on `reverse_iterator`'s converting constructor: both `convertible_to<reverse_iterator<int*>, reverse_iterator<const int*>>` and `convertible_to<reverse_iterator<const int*>, reverse_iterator<int*>>` evaluate to `true`, despite that `reverse_iterator<int*>`'s converting constructor template is ill-formed when instantiated for `reverse_iterator<const int*>`. This apparent bi-convertibility results in ambiguity when trying to determine `common_reference_t<const reverse_iterator<int*>&, const reverse_iterator<const int*>&>`, causing the `common_reference` requirement in `three_way_comparable_with` to fail.

I think we should correct this by constraining `reverse_iterator`'s conversion constructor (and converting assignment operator, while we're here) correctly so we can use the concept to determine when it's ok to compare specializations of `reverse_iterator` with `<=>`.

`move_iterator` has similar issues due to its similarly unconstrained conversions. We should fix both similarly.

[2020-07-17; Priority set to 2 in telecon]

[2020-07-26; Reflector poll]

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

[2020-11-09 Approved In November virtual meeting. Status changed: Tentatively Ready → WP.]

Proposed resolution:

This wording is relative to N4861.

1. Modify 23.5.3.4 [move.iter.cons] as indicated:

   > [Drafting note: this incorporates and supercedes the P/R of LWG 3265.]

   >     constexpr move_iterator();

   > > -1- Effects: Constructs a `move_iterator`, v Value-initializes ing `current`. Iterator operations applied to the resulting iterator have defined behavior if and only if the corresponding operations are defined on a value-initialized iterator of type `Iterator`.

   >     constexpr explicit move_iterator(Iterator i);

   > > -2- Effects: Constructs a `move_iterator`, i Initializes ing `current` with `std::move(i)`.

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

   > > -3- Mandates: `U` is convertible to `Iterator` Constraints: `is_same_v<U, Iterator>` is `false` and `const U&` models `convertible_to<Iterator>`.

   > > -4- Effects: Constructs a `move_iterator`, i Initializes ing `current` with `u.currentbase()`.

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

   > > -5- Mandates: `U` is convertible to `Iterator` 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.currentbase()` to `current`.

2. Modify 23.5.1.4 [reverse.iter.cons] as indicated:

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

   > > -?- Constraints: `is_same_v<U, Iterator>` is `false` and `const U&` models `convertible_to<Iterator>`.

   > > -3- Effects: Initializes `current` with `u.current`.

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

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

   > > -4- Effects: Assigns `u.currentbase()` to `current`.

   > > -5- Returns: `*this`.