Given
std::vector first = /* some given data */, second;
I want to move all elements e
which satisfy some co
@T.C. has provided a perfectly working solution. However, at a first glance, one may not understand what the intend of that code is. So, it might be not perfect, but I tend to prefer something like this:
template<class InputIt, class OutputIt, class InputContainer, class UnaryPredicate>
OutputIt move_and_erase_if(InputIt first, InputIt last, InputContainer& c, OutputIt d_first, UnaryPredicate pred)
{
auto dist = std::distance(first, last);
while (first != last)
{
if (pred(*first))
{
*d_first++ = std::move(*first);
first = c.erase(first);
last = std::next(first, --dist);
}
else
{
++first;
--dist;
}
}
return d_first;
}
The reason why move_if
doesn't exist is because it would bloat the library. Either use copy_if
with move iterator or write it yourself.
copy_if(move_iterator<I>(f), move_iterator<I>(l), out);
Here is an implementation by Jonas_No found at channel9.
template <typename FwdIt, typename Container, typename Predicate>
inline FwdIt move_if(FwdIt first, FwdIt last, Container &cont, Predicate pred)
{
if (first == last)
return last; // Empty so nothing to move
const size_t size = count_if(first, last, pred);
if (size == 0)
return last; // Nothing to move
cont.resize(size);
FwdIt new_end = first;
auto c = cont.begin();
for (auto i = first; i != last; ++i)
{
if (pred(*i)) // Should it move it ?
*c++ = move(*i);
else
*new_end++ = move(*i);
}
return new_end;
}
If the moved-from elements can stay where they are in first
, then just use copy_if
with move_iterator
.
std::copy_if(std::make_move_iterator(first.begin()),
std::make_move_iterator(first.end()),
std::back_inserter(second), cond);
If the moved-from elements should be erased from first
, I'd do
// partition: all elements that should not be moved come before
// (note that the lambda negates cond) all elements that should be moved.
// stable_partition maintains relative order in each group
auto p = std::stable_partition(first.begin(), first.end(),
[&](const auto& x) { return !cond(x); });
// range insert with move
second.insert(second.end(), std::make_move_iterator(p),
std::make_move_iterator(first.end()));
// erase the moved-from elements.
first.erase(p, first.end());
Or partition_copy
with a move_iterator
, followed by assignment:
std::vector<T> new_first;
std::partition_copy(std::make_move_iterator(first.begin()),
std::make_move_iterator(first.end()),
std::back_inserter(second), std::back_inserter(new_first), cond);
first = std::move(new_first);