Title
common_iterator::operator->() should return by value
Status
c++23
Section
[common.iter.access]
Submitter
Jonathan Wakely

Created on 2022-02-12.00:00:00 last changed 4 months ago

Messages

Date: 2022-07-25.20:32:58

Proposed resolution:

This wording is relative to N4901.

  1. Modify [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 [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_);
        }
      };
      
Date: 2022-07-25.00:00:00

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

Date: 2022-07-15.00:00:00

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

Date: 2022-03-15.00:00:00

[ 2022-03-04; Reflector poll ]

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

Date: 2022-02-12.00:00:00

[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 [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.

History
Date User Action Args
2023-11-22 15:47:43adminsetstatus: wp -> c++23
2022-07-25 20:32:58adminsetmessages: + msg12639
2022-07-25 20:32:58adminsetstatus: ready -> wp
2022-07-25 20:28:19adminsetmessages: + msg12613
2022-03-04 14:33:21adminsetmessages: + msg12391
2022-03-04 14:33:21adminsetstatus: new -> ready
2022-02-14 12:56:40adminsetmessages: + msg12371
2022-02-12 00:00:00admincreate