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.

### 3672. `common_iterator::operator->()` should return by value

Section: 25.5.5.4 [common.iter.access] Status: WP Submitter: Jonathan Wakely Opened: 2022-02-12 Last modified: 2022-07-25

Priority: Not Prioritized

View all other issues in [common.iter.access].

View all issues with WP status.

Discussion:

25.5.5.4 [common.iter.access] p5 (5.1) says that `common_iterator<T*, S>::operator->()` returns `std::get<T*>(v_)` which has type `T* const&`. That means that `iterator_traits::pointer` is `T* const&` as well (this was recently clarified by LWG 3660). We have an actual pointer here, why are we returning it by reference?

For the three bullet points in 25.5.5.4 [common.iter.access] p5, the second and third return by value anyway, so `decltype(auto)` is equivalent to `auto`. For the first bullet, it would make a lot more sense for raw pointers to be returned by value. That leaves the case where the iterator has an `operator->()` member, which could potentially benefit from returning by reference. But it must return something that is iterator-like or pointer-like, which we usually just pass by value. Casey suggested we should just change `common_iterator<I, S>::operator->()` to return by value in all cases.

Libstdc++ has always returned by value, as an unintended consequence of using a union instead of `std::variant<I, S>`, so that it doesn't use `std::get<I>` to return the member.

[2022-03-04; Reflector poll]

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

[2022-07-15; LWG telecon: move to Ready]

[2022-07-25 Approved at July 2022 virtual plenary. Status changed: Ready → WP.]

Proposed resolution:

This wording is relative to N4901.

1. Modify 25.5.5.1 [common.iterator], class template `common_iterator` synopsis, as indicated:

   >     […]
   >     constexpr decltype(auto) operator*();
   >     constexpr decltype(auto) operator*() const
   >       requires dereferenceable<const I>;
   >     constexpr decltype(auto) operator->() const
   >       requires see below;
   >     […]

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: […]

   > > -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, 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_);
   > >    >       }
   > >    >     };