Как эмулировать remove_unless

У меня есть код, чтобы удалить все элементы из std::vector<int> которые меньше чем некоторые int limit, Я написал несколько функций, которые частично применяют лямбда-выражения:

auto less_than_limit = [](int limit) {
return [=](int elem) {
return limit > elem;
};
};

auto less_than_three = less_than_limit(3);

Когда я проверяю это с std::vector<int> v{1,2,3,4,5};Я получаю ожидаемые результаты:

for(auto e: v) {
std::cout << less_than_three(e) << " ";
}
// 1 1 0 0 0

Я могу легко удалить все элементы меньше трех:

auto remove_less_than_three = std::remove_if(std::begin(v), std::end(v), less_than_three);

v.erase(remove_less_than_three, v.end());

for(auto e: v) {
std::cout << e << " ";
}
// 3 4 5

Как бы удалить элементы больше или равные 3, используя less_than_three?

Я пробовал оборачивать less_than_three в std::not1, но получил ошибки:

/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/bits/stl_function.h:742:11: error: no type named 'argument_type' in 'struct main()::<lambda(int)>::<lambda(int)>'
class unary_negate
^
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/bits/stl_function.h:755:7: error: no type named 'argument_type' in 'struct main()::<lambda(int)>::<lambda(int)>'
operator()(const typename _Predicate::argument_type& __x) const

/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/bits/predefined_ops.h:234:30: error: no match for call to '(std::unary_negate<main()::<lambda(int)>::<lambda(int)> >) (int&)'
{ return bool(_M_pred(*__it)); }
^

Я тогда попробовал std::not1(std::ref(less_than_three)), но получил эти ошибки:

/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/bits/stl_function.h:742:11: error: no type named 'argument_type' in 'class std::reference_wrapper<main()::<lambda(int)>::<lambda(int)> >'
class unary_negate
^
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/bits/stl_function.h:755:7: error: no type named 'argument_type' in 'class std::reference_wrapper<main()::<lambda(int)>::<lambda(int)> >'
operator()(const typename _Predicate::argument_type& __x) const
^
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/bits/predefined_ops.h:234:30: error: no match for call to '(std::unary_negate<std::reference_wrapper<main()::<lambda(int)>::<lambda(int)> > >) (int&)'
{ return bool(_M_pred(*__it)); }
^

Как я могу отменить функцию в std::remove_if не меняя логику моей лямбды? Другими словами, как я могу подражать remove_unless?

6

Решение

std::not1 предполагает, что ваш функциональный объект будет производным от std::unary_functionили, по крайней мере, предоставьте тот же интерфейс, так что он будет иметь typedefs для result_type а также argument_type,

Поскольку лямбда не будет определять их, вы не сможете использовать not1 на них.

Очевидным выбором будет создание чего-то похожего на not1 самостоятельно, но используя более современные методы, чтобы обнаружить / передать тип аргумента / результата из того, что он изменяет.

Если вы действительно хотите использовать not1тогда самым разумным подходом было бы сделать сравнение с std::less а также std::bind чтобы указать значение, с которым вы собираетесь сравнивать (то есть, это в основном C ++ 03, поэтому, если вы собираетесь его использовать, вы пишете все в стиле C ++ 03).

7

Другие решения

not1 несколько устарел (и требует, чтобы функтор предоставлял определенные определения типов членов, чего явно не имеет лямбда).

Вы должны будете написать отрицатель самостоятельно:

auto negate = [] (auto&& f) {return [f=std::forward<decltype(f)>(f)]
(auto&&... args) {return !f(std::forward<decltype(args)>(args)...);};};

демонстрация.

11

Вы также можете определить тип возврата лямбда с std :: function.

auto remove_gte_three = std::remove_if(std::begin(v), std::end(v), std::not1(std::function<int(int)>(less_than_three)));
4

Старый способ с not1 () отрицателем (C ++ 11):

// You apply the not1() negator adapter
// to the result of  less_than_three() like this:
std::function<bool(int)> f = less_than_three;
auto it = remove_if(begin(v), end(v), not1(f));

Новый способ с лямбда (C ++ 14):

// Or with lambda you can negate an unary predicate.
// Thanks to Stephan T. Lavavej
template <typename T, typename Predicate>
void keep_if(std::vector<T>& v, Predicate pred)
{
auto notpred = [&pred](const T& t) { return !pred(t); };
v.erase(remove_if(v.begin(), v.end(), notpred), v.end());
}

Использование:

keep_if(v, less_than_three);

Или более общее решение (C ++ 14):

template <ForwardIterator I, Predicate P>
I remove_if_not(I first, I last, P pred)
{
return std::remove_if(first, last,
[&](const ValueType(I)& x){ return !pred(x); });
}

Использование:

auto p = remove_if_not(begin(v), end(v), less_than_three);
v.erase(p, v.end());
// Result: 1 2
1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector