This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
Section: 26.7.9.3 [range.transform.iterator] Status: WP Submitter: Tim Song Opened: 2021-02-03 Last modified: 2021-06-07
Priority: 2
View all other issues in [range.transform.iterator].
View all issues with WP 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.
Consider the following test case: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 Xs by their x data member" (as ranges::sort(v, {}, &X::x) would do), nor "sort the x data member of these Xs 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 26.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 to ranges::iter_swap(x.current_, y.current_).