join_view::iterator
's iter_swap
is underconstrainedSection: 25.7.14.3 [range.join.iterator] Status: C++23 Submitter: Casey Carter Opened: 2021-01-28 Last modified: 2023-11-22
Priority: Not Prioritized
View all other issues in [range.join.iterator].
View all issues with C++23 status.
Discussion:
std::ranges::join_view::iterator
's hidden friend iter_swap
is specified in
25.7.14.3 [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.
[2021-03-12; Reflector poll]
Set status to Tentatively Ready after six votes in favour during reflector poll.
[2021-06-07 Approved at June 2021 virtual plenary. Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4878.
Modify 25.7.14.3 [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 insertedrequires
.
[…]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_);