3574. common_iterator should be completely constexpr-able

Section: 24.5.5.1 [common.iterator] Status: C++23 Submitter: Hewill Kang Opened: 2021-07-21 Last modified: 2023-11-22

Priority: 3

View other active issues in [common.iterator].

View all other issues in [common.iterator].

View all issues with C++23 status.

Discussion:

After P2231R1, variant becomes completely constexpr-able, which means that common_iterator can also be completely constexpr-able.

[2021-08-20; Reflector poll]

Set priority to 3 after reflector poll.

[2021-08-23; Reflector poll]

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

[2021-10-14 Approved at October 2021 virtual plenary. Status changed: Voting → WP.]

Proposed resolution:

This wording is relative to N4892.

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

    namespace std {
      template<input_or_output_iterator I, sentinel_for<I> S>
        requires (!same_as<I, S> && copyable<I>)
      class common_iterator {
      public:
        constexpr common_iterator() requires default_initializable<I> = default;
        constexpr common_iterator(I i);
        constexpr common_iterator(S s);
        template<class I2, class S2>
          requires convertible_to<const I2&, I> && convertible_to<const S2&, S>
            constexpr common_iterator(const common_iterator<I2, S2>& x);
            
        template<class I2, class S2>
          requires convertible_to<const I2&, I> && convertible_to<const S2&, S> &&
                   assignable_from<I&, const I2&> && assignable_from<S&, const S2&>
          constexpr common_iterator& operator=(const common_iterator<I2, S2>& x);
    
        constexpr decltype(auto) operator*();
        constexpr decltype(auto) operator*() const
          requires dereferenceable<const I>;
        constexpr decltype(auto) operator->() const
          requires see below;
     
        constexpr common_iterator& operator++();
        constexpr decltype(auto) operator++(int);
    
        template<class I2, sentinel_for<I> S2>
          requires sentinel_for<S, I2>
        friend constexpr bool operator==(
          const common_iterator& x, const common_iterator<I2, S2>& y);
        template<class I2, sentinel_for<I> S2>
          requires sentinel_for<S, I2> && equality_comparable_with<I, I2>
        friend constexpr bool operator==(
          const common_iterator& x, const common_iterator<I2, S2>& y);
    
        template<sized_sentinel_for<I> I2, sized_sentinel_for<I> S2>
          requires sized_sentinel_for<S, I2>
        friend constexpr iter_difference_t<I2> operator-(
          const common_iterator& x, const common_iterator<I2, S2>& y);
    
        friend constexpr iter_rvalue_reference_t<I> iter_move(const common_iterator& i)
          noexcept(noexcept(ranges::iter_move(declval<const I&>())))
            requires input_iterator<I>;
        template<indirectly_swappable<I> I2, class S2>
          friend constexpr void iter_swap(const common_iterator& x, const common_iterator<I2, S2>& y)
            noexcept(noexcept(ranges::iter_swap(declval<const I&>(), declval<const I2&>())));
    
      private:
        variant<I, S> v_; // exposition only
      };
      […]
    }
    
  2. Modify 24.5.5.3 [common.iter.const] as indicated:

    template<class I2, class S2>
      requires convertible_to<const I2&, I> && convertible_to<const S2&, S> &&
               assignable_from<I&, const I2&> && assignable_from<S&, const S2&>
        constexpr common_iterator& operator=(const common_iterator<I2, S2>& x);
    

    -5- Preconditions: x.v_.valueless_by_exception() is false.

    […]

  3. Modify 24.5.5.4 [common.iter.access] as indicated:

    constexpr decltype(auto) operator*();
    constexpr decltype(auto) operator*() const
      requires dereferenceable<const I>;
    

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

    […]

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

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

    […]

  4. Modify 24.5.5.5 [common.iter.nav] as indicated:

    constexpr common_iterator& operator++();
    

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

    […]

    constexpr decltype(auto) operator++(int);
    

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

    […]

  5. Modify 24.5.5.6 [common.iter.cmp] as indicated:

    template<class I2, sentinel_for<I> S2>
      requires sentinel_for<S, I2>
    friend constexpr bool operator==(
      const common_iterator& x, const common_iterator<I2, S2>& y);
    

    -1- Preconditions: […]

    template<class I2, sentinel_for<I> S2>
      requires sentinel_for<S, I2> && equality_comparable_with<I, I2>
    friend constexpr bool operator==(
      const common_iterator& x, const common_iterator<I2, S2>& y);
    

    -3- Preconditions: […]

    template<sized_sentinel_for<I> I2, sized_sentinel_for<I> S2>
      requires sized_sentinel_for<S, I2>
    friend constexpr iter_difference_t<I2> operator-(
      const common_iterator& x, const common_iterator<I2, S2>& y);
    

    -5- Preconditions: […]

  6. Modify 24.5.5.7 [common.iter.cust] as indicated:

    friend constexpr iter_rvalue_reference_t<I> iter_move(const common_iterator& i)
      noexcept(noexcept(ranges::iter_move(declval<const I&>())))
        requires input_iterator<I>;
    

    -1- Preconditions: […]

    template<indirectly_swappable<I> I2, class S2>
      friend constexpr void iter_swap(const common_iterator& x, const common_iterator<I2, S2>& y)
        noexcept(noexcept(ranges::iter_swap(declval<const I&>(), declval<const I2&>())));
    

    -3- Preconditions: […]