https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118209
Bug ID: 118209
Summary: ranges::sort doesn't use iter_move, cannot sort zip of
move-only type
Product: gcc
Version: 14.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
Assignee: unassigned at gcc dot gnu.org
Reporter: arthur.j.odwyer at gmail dot com
Target Milestone: ---
Bug #105609 is related, i.e. it's about using std::move(*it) where ADL
iter_move(it) is required; but I think this new one differs enough to file it
separately. This one transitively affects make_heap and partial_sort.
This initially came from StackOverflow:
https://stackoverflow.com/questions/12227474/can-iter-swap-be-specialised/75535132?noredirect=1#comment139852610_75535132
// https://godbolt.org/z/jqYE9Tnqe
#include <algorithm>
#include <ranges>
#include <vector>
struct F {
int a = -1;
explicit F(int d) : a(d) { }
F(const F&) = delete;
F(F&& o) : a(o.a) { }
void operator=(const F&) = delete;
F& operator=(F&& o) {
a = o.a;
return *this;
}
auto operator<=>(const F&) const = default;
};
int main() {
int a[] = {3,2,1};
std::vector<F> v(a, a+3);
// sorting v is OK
std::ranges::sort(v);
// sorting zip(v) doesn't compile
std::ranges::sort(std::views::zip(v));
}
include/c++/15.0.0/bits/stl_heap.h:355:15: error: no viable conversion from
'typename std::remove_reference<tuple<F &>>::type' (aka 'std::tuple<F &>') to
'_ValueType' (aka 'std::tuple<F>')
355 | _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This happens inside __make_heap, called from __partial_sort.
The problem is that it's calling `std::move(*iter)` to get an xvalue
zip_view::reference, which then converts to an lvalue F, which can't be copied
because F is move-only. What we need instead is to call zip_view::iterator's
ADL `iter_move(iter)`, to give us an xvalue F directly.
libc++ and MS STL both handle this OK.