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.

### 3520. `iter_move` and `iter_swap` are inconsistent for `transform_view::iterator`

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 `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.

1. 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_)`.