3955. Add noexcept to several repeat_view[::iterator] member functions

Section: 25.6.5.2 [range.repeat.view], 25.6.5.3 [range.repeat.iterator] Status: New Submitter: Hewill Kang Opened: 2023-07-06 Last modified: 2023-10-30

Priority: 3

View all other issues in [range.repeat.view].

View all issues with New status.

Discussion:

Several member functions of repeat_view::iterator only operate on its integer member, indicating that they do not throw.

Similarly, repeat_view::size should also be noexcept since it just performs the integer conversion.

[2023-10-30; Reflector poll]

Set priority to 3 after reflector poll. Some votes for NAD. "The iterator changes violate the Lakos rule."

Proposed resolution:

This wording is relative to N4950.

  1. Modify 25.6.5.2 [range.repeat.view], class template repeat_view synopsis, as indicated:

    namespace std::ranges {
      […]
      template<move_constructible T, semiregular Bound = unreachable_sentinel_t>
        requires (is_object_v<T> && same_as<T, remove_cv_t<T>> &&
                  (integer-like-with-usable-difference-type<Bound> ||
                   same_as<Bound, unreachable_sentinel_t>))
      class repeat_view : public view_interface<repeat_view<T, Bound>> {
      private:
        […]
      public:
        […]
    
        constexpr auto size() const noexcept requires (!same_as<Bound, unreachable_sentinel_t>);
      };
      […]
    }
    

    […]

    constexpr auto size() const noexcept requires (!same_as<Bound, unreachable_sentinel_t>);
    

    -9- Effects: Equivalent to: return to-unsigned-like(bound_);

  2. Modify 25.6.5.3 [range.repeat.iterator], class repeat_view::iterator synopsis, as indicated:

    namespace std::ranges {
      template<move_constructible T, semiregular Bound>
        requires (is_object_v<T> && same_as<T, remove_cv_t<T>> &&
                  (integer-like-with-usable-difference-type<Bound> ||
                   same_as<Bound, unreachable_sentinel_t>))
      class repeat_view<T, Bound>::iterator {
      private:
       using index-type =                          // exposition only
          conditional_t<same_as<Bound, unreachable_sentinel_t>, ptrdiff_t, Bound>;
       const T* value_ = nullptr;                  // exposition only
       index-type current_ = index-type();         // exposition only
    
       constexpr explicit iterator(const T* value, index-type b = index-type());   // exposition only
    
      public:
        […]
        constexpr iterator& operator++() noexcept;
        constexpr iterator operator++(int) noexcept;
    
        constexpr const T& operator[](difference_type n) const noexcept;
    
        friend constexpr bool operator==(const iterator& x, const iterator& y) noexcept;
        friend constexpr auto operator<=>(const iterator& x, const iterator& y) noexcept;
    
        friend constexpr difference_type operator-(const iterator& x, const iterator& y) noexcept;
      };
    }
    

    […]

    constexpr iterator& operator++() noexcept;
    

    -5- Effects: Equivalent to:

    ++current_;
    return *this;
    
    constexpr iterator operator++(int) noexcept;
    

    -6- Effects: Equivalent to:

    auto tmp = *this;
    ++*this;
    return tmp;
    

    […]

    friend constexpr bool operator==(const iterator& x, const iterator& y) noexcept;
    

    -15- Effects: Equivalent to: return x.current_ == y.current_;

    friend constexpr auto operator<=>(const iterator&x, const iterator& y) noexcept;
    

    -16- Effects: Equivalent to: return x.current_ <=> y.current_;

    […]

    friend constexpr difference_type operator-(const iterator& x, const iterator& y) noexcept;
    

    -19- Effects: Equivalent to:

    return static_cast<difference_type>(x.current_) - static_cast<difference_type>(y.current_);