Title
join_view::iterator's iter_swap is underconstrained
Status
ready
Section
[range.join.iterator]
Submitter
Casey Carter

Created on 2021-01-28.00:00:00 last changed 1 month ago

Messages

Date: 2021-03-12.15:09:15

Proposed resolution:

This wording is relative to N4878.

  1. Modify [range.join.iterator] as indicated:

    [Drafting note: If 3500 is accepted before this issue, it is kindly suggested to the Project Editor to apply the equivalent replacement of "iterator_t<range_reference_t<Base>>" by "InnerIter" to the newly inserted requires.

    namespace std::ranges {
      template<input_range V>
        requires view<V> && input_range<range_reference_t<V>> &&
                 (is_reference_v<range_reference_t<V>> ||
                 view<range_value_t<V>>)
      template<bool Const>
      struct join_view<V>::iterator {
        […]
        
        friend constexpr void iter_swap(const iterator& x, const iterator& y)
          noexcept(noexcept(ranges::iter_swap(x.inner_, y.inner_)))
          requires indirectly_swappable<iterator_t<range_reference_t<Base>>>;
      };
    }
    
    […]
    friend constexpr void iter_swap(const iterator& x, const iterator& y)
      noexcept(noexcept(ranges::iter_swap(x.inner_, y.inner_)))
      requires indirectly_swappable<iterator_t<range_reference_t<Base>>>;
    

    -16- Effects: Equivalent to: return ranges::iter_swap(x.inner_, y.inner_);

Date: 2021-03-15.00:00:00

[ 2021-03-12; Reflector poll ]

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

Date: 2021-01-28.00:00:00

std::ranges::join_view::iterator's hidden friend iter_swap is specified in [range.join.iterator]/16 as:

friend constexpr void iter_swap(const iterator& x, const iterator& y)
  noexcept(noexcept(ranges::iter_swap(x.inner_, y.inner_)));

-16- Effects: Equivalent to: return ranges::iter_swap(x.inner_, y.inner_);

Notably, the expression ranges::iter_swap(meow, woof) is not valid for all iterators meow and woof, or even all input iterators of the same type as is the case here. This iter_swap overload should be constrained to require the type of iterator::inner_ (iterator_t<range_reference_t<maybe-const<Const, V>>>) to satisfy indirectly_swappable. Notably this is already the case for iter_swap friends of every other iterator adaptor in the Standard Library (reverse_iterator, move_iterator, common_iterator, counted_iterator, filter_view::iterator, transform_view::iterator, and split_view::inner-iterator). The omission for join_view::iterator seems to have simply been an oversight.

History
Date User Action Args
2021-03-12 15:09:15adminsetmessages: + msg11732
2021-03-12 15:09:15adminsetstatus: new -> ready
2021-01-31 14:13:40adminsetmessages: + msg11672
2021-01-28 00:00:00admincreate