I was reading through the MSVC STL implementation of std::ranges::remove
when I noticed the following line:
_First = _RANGES _Find_if_unchecked(_STD move(_First), _Last, _Pred, _Proj);
Indeed, cppreference has the following line in their 'possible implementation' too:
first = ranges::find_if(std::move(first), last, pred, proj);
What's confusing to me is, I've just about never seen anyone move an iterator; they're typically cheap to copy (or at least should be), and even if this were an issue of copies, we could take a universal reference and std::forward
the iterator to find_if
instead surely?
What advantage does casting to an rvalue reference have here over simply passing by value?
CodePudding user response:
ranges::find_if
accepts input_iterator
, which is not necessarily copyable
(an example in the standard is basic_istream_view::iterator
).
In the C 20 iterator system, only iterators that model forward_iterator
are guaranteed to be copyable, so std::move
is necessary here.
and even if this were an issue of copies, we could take a universal reference and std::forward the iterator to find_if instead surely?
Iterators are generally passed by value.
When the first
iterator is not guaranteed to be copyable, we need to transfer its ownership to ranges::find_if
via std::move
, and re-accept its ownership via its return.
(Although in your example std::move
can be omitted since ranges::remove
already requires forward_iterator
)