Title
iter_move and iter_swap are inconsistent for transform_view::iterator
Status
c++23
Section
[range.transform.iterator]
Submitter
Tim Song

Created on 2021-02-03.00:00:00 last changed 12 months ago

Messages

Date: 2021-06-07.16:58:04

Proposed resolution:

This wording is relative to N4878.

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

Date: 2021-06-07.00:00:00

[ 2021-06-07 Approved at June 2021 virtual plenary. Status changed: Voting → WP. ]

Date: 2021-03-15.00:00:00

[ 2021-03-12; LWG telecon ]

Set status to Tentatively Ready after discussion and poll.

FAN
900

Date: 2021-03-15.00:00:00

[ 2021-03-12; Reflector poll ]

Set priority to 2 following reflector poll.

Date: 2021-02-03.00:00:00

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.

History
Date User Action Args
2023-11-22 15:47:43adminsetstatus: wp -> c++23
2021-06-07 16:58:04adminsetmessages: + msg11892
2021-06-07 16:58:04adminsetstatus: voting -> wp
2021-05-26 21:11:22adminsetstatus: ready -> voting
2021-04-19 14:17:33adminsetmessages: + msg11765
2021-04-19 14:17:33adminsetstatus: new -> ready
2021-03-12 15:08:32adminsetmessages: + msg11731
2021-02-07 17:15:44adminsetmessages: + msg11681
2021-02-03 00:00:00admincreate