iter_move
and iter_swap
are inconsistent for transform_view::iterator
Section: 25.7.9.3 [range.transform.iterator] Status: C++23 Submitter: Tim Song Opened: 2021-02-03 Last modified: 2023-11-22
Priority: 2
View all other issues in [range.transform.iterator].
View all issues with C++23 status.
Discussion:
For transform_view::iterator
, iter_move
is specified to operate on the
transformed value but iter_swap
is specified to operate on the underlying iterator.
struct X { int x; int y; }; std::vector<X> v = {...}; auto t = v | views::transform(&X::x); ranges::sort(t);
iter_swap
on t
's iterators would swap the whole X
, including the
y
part, but iter_move
will only move the x
data member and leave
the y
part intact. Meanwhile, ranges::sort
can use both iter_move
and
iter_swap
, and does so in at least one implementation. The mixed behavior means that we
get neither "sort X
s by their x
data member" (as ranges::sort(v, {}, &X::x)
would do), nor "sort the x
data member of these X
s and leave the rest unchanged",
as one might expect, but instead some arbitrary permutation of y
. This seems like a
questionable state of affairs.
[2021-03-12; Reflector poll]
Set priority to 2 following reflector poll.
[2021-03-12; LWG telecon]
Set status to Tentatively Ready after discussion and poll.
F | A | N |
---|---|---|
9 | 0 | 0 |
[2021-06-07 Approved at June 2021 virtual plenary. Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4878.
Modify 25.7.9.3 [range.transform.iterator] as indicated:
[…]namespace std::ranges { template<input_range V, copy_constructible F> requires view<V> && is_object_v<F> && regular_invocable<F&, range_reference_t<V>> && can-reference<invoke_result_t<F&, range_reference_t<V>>> template<bool Const> class transform_view<V, F>::iterator { […]friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(noexcept(ranges::iter_swap(x.current_, y.current_))) requires indirectly_swappable<iterator_t<Base>>;}; }friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(noexcept(ranges::iter_swap(x.current_, y.current_))) requires indirectly_swappable<iterator_t<Base>>;
-23- Effects: Equivalent toranges::iter_swap(x.current_, y.current_)
.