This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Tentatively NAD status.

### 3727. `reverse_iterator`/`common_iterator`'s `operator->` should not require the underlying iterator's `operator->` to be a `const` member function

Section: 25.5.1.6 [reverse.iter.elem], 25.5.5.4 [common.iter.access] Status: Tentatively NAD Submitter: Hewill Kang Opened: 2022-06-27 Last modified: 2022-08-23

Priority: Not Prioritized

View other active issues in [reverse.iter.elem].

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

View all issues with Tentatively NAD status.

Discussion:

For non-pointer types, `reverse_iterator::operator->` requires that the `Iterator` must have an `operator->()` with `const`-qualifier, whereas in the Effects clause, it always invokes the non-`const` object's `operator->()`.

`common_iterator::operator->` also requires that `I::operator->()` must be `const`-qualified, which seems reasonable since the return type of `get<I>(v_)` is `const I&`. However, LWG 3672 makes `common_iterator::operator->()` always return a value, which makes it unnecessary to detect the constness of `I::operator->()`, because it will be invoked with a non-`const` returned object anyway.

I think we should remove this constraint as I don't see the benefit of doing that. Constraining iterator's `operator->()` to be `const` and finally invoking non-`const` overload doesn't feel right to me either. In `<ranges>`, the exposition-only constraint `has-arrow` (26.5.2 [range.utility.helpers]) for `operator->()` does not require that the underlying iterator's `operator->()` to be `const`, we should make them consistent, and I believe this relaxation of constraints can bring some value.

Daniel:

This issue's second part of the resolution actually depends on 3672 being applied. But note that the reference wording below is still N4910.

[2022-08-23; Reflector poll: NAD]

Implicit variations apply to those requires-expressions, so calling as non-const (and rvalue) is fine. The PR actually loses that property and makes those overloads truly underconstrained. Motivation for relaxing it is vague. As for consistency, we should fix has-arrow instead.

Proposed resolution:

This wording is relative to N4910.

1. Modify 25.5.1.6 [reverse.iter.elem] as indicated:

   >     constexpr pointer operator->() const
   >       requires (is_pointer_v<Iterator> ||
   >                 requires(const Iterator i) { i.operator->(); });

   > > -2- Effects:

   > > 1. (2.1) — If `Iterator` is a pointer type, equivalent to: `return prev(current);`

   > > 2. (2.2) — Otherwise, equivalent to: `return prev(current).operator->();`

2. Modify 25.5.5.4 [common.iter.access] as indicated:

   >     constexpr decltype(auto) operator->() const
   >       requires see below;

   > > -3- The expression in the requires-clause is equivalent to:

   > > >       indirectly_readable<const I> &&
   > > >       (requires(const I& i) { i.operator->(); } ||
   > > >       is_reference_v<iter_reference_t<I>> ||
   > > >       constructible_from<iter_value_t<I>, iter_reference_t<I>>)

   > > -4- Preconditions: `holds_alternative<I>(v_)` is `true`.

   > > -5- Effects:

   > > 1. (5.1) — If `I` is a pointer type or if the expression `get<I>(v_).operator->()` is well-formed `requires(I i) { i.operator->(); }` is `true`, equivalent to: `return get<I>(v_);`

   > > 2. (5.2) — Otherwise, if `iter_reference_t<I>` is a reference type, equivalent to:

   > >    >       auto&& tmp = *get<I>(v_);
   > >    >       return addressof(tmp);

   > > 3. (5.3) — Otherwise, equivalent to: `return proxy(*get<I>(v_));` where `proxy` is the exposition-only class:

   > >    >       class proxy {
   > >    >         iter_value_t<I> keep_;
   > >    >         constexpr proxy(iter_reference_t<I>&& x)
   > >    >           : keep_(std::move(x)) {}
   > >    >       public:
   > >    >         constexpr const iter_value_t<I>* operator->() const noexcept {
   > >    >           return addressof(keep_);
   > >    >         }
   > >    >       };

   > > […]