3853. basic_const_iterator<volatile int*>::operator-> is ill-formed

Section: 24.5.3 [const.iterators] Status: C++23 Submitter: Hewill Kang Opened: 2023-01-06 Last modified: 2023-11-22

Priority: Not Prioritized

View other active issues in [const.iterators].

View all other issues in [const.iterators].

View all issues with C++23 status.

Discussion:

Currently, basic_const_iterator::operator-> constrains the value type of the underlying iterator to be only the cv-unqualified type of its reference type, which is true for raw pointers.

However, since it also explicitly specifies returning a pointer to a const value type, this will cause a hard error when the value type is actually volatile-qualified:

std::basic_const_iterator<volatile int*> it;
auto* p = it.operator->(); // invalid conversion from 'volatile int*' to 'const int*'

The proposed resolution changes the return type from const value_type* to const auto*, which makes it deduce the correct type in the above example, i.e. const volatile int*.

[2023-02-01; Reflector poll]

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

[2023-02-13 Approved at February 2023 meeting in Issaquah. Status changed: Voting → WP.]

Proposed resolution:

This wording is relative to N4917.

  1. Modify 24.5.3 [const.iterators] as indicated:

    namespace std {
      template<class I>
        concept not-a-const-iterator = see below;
    
      template<input_iterator Iterator>
      class basic_const_iterator {
        Iterator current_ = Iterator();                             // exposition only
        using reference = iter_const_reference_t<Iterator>;         // exposition only
      
      public:
        […]
        constexpr reference operator*() const;
        constexpr const autovalue_type* operator->() const
           requires is_lvalue_reference_v<iter_reference_t<Iterator>> &&
                    same_as<remove_cvref_t<iter_reference_t<Iterator>>, value_type>;
        […]
      };
    }
    
    […]
    constexpr const autovalue_type* operator->() const
      requires is_lvalue_reference_v<iter_reference_t<Iterator>> &&
               same_as<remove_cvref_t<iter_reference_t<Iterator>>, value_type>;
    

    -7- Returns: If Iterator models contiguous_iterator, to_address(current_); otherwise, addressof(*current_).