Использование отрицания UnaryPredicate в идиоме erase-remove

Рассмотрим следующий сценарий:

bool is_odd(int i)
{
return (i % 2) != 0;
}
int main()
{
// ignore the method of vector initialization below.
// assume C++11 is not to be used.
std::vector<int> v1 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
std::vector<int> v2 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

// removes all odd numbers, OK
v1.erase( std::remove_if(v1.begin(), v1.end(), is_odd), v1.end() );

// remove all even numbers
v2.erase( std::remove_if(v2.begin(), v2.end(), ???), v2.end() );
}

Могу ли я использовать то же самое is_odd() UnaryPredicate для удаления четных чисел, как и ожидалось в последней строке main(), Или я должен обязательно написать is_even() хотя это будет только

bool is_even(int i)
{
!is_odd(i);
}

5

Решение

проверить станд :: not1 функция. он делает то, что вы хотите.

v2.erase( std::remove_if(v2.begin(), v2.end(), std::not1(std::ptr_fun(is_odd))), v2.end() );

Живой пример

В любом случае, если это зависит от меня, плюс C ++ 11 доступен, я бы предпочел:

 v2.erase( std::remove_if(v2.begin(), v2.end(), [&](auto/* or the type */ const& item){return !is_odd(item);}), v2.end() );

потому что, насколько я помню std::not1 было полезно раньше lambda был доступен.

9

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

Ты можешь использовать std::not1, К сожалению, std::not1 требует аргумента объекта функции с вложенным argument_type а также result_type типы. То есть его нельзя использовать напрямую. Вместо этого необходимо сочетать использование с std::ptr_fun при использовании отрицателя с нормальной функцией:

    v2.erase( std::remove_if(v2.begin(), v2.end(), std::not1(std::ptr_fun(is_odd))), v2.end() );

На последнем заседании комитета std::not_fn был перенесен из Основы библиотеки TS 2 в рабочий проект. То есть есть надежда, что с C ++ 17 есть лучшее предложение для общего отрицателя.

В общем, веселье прекращается, когда вам нужно использовать любой из std::*_fun функции. Как уже отмечали другие, разумно использовать вместо этого лямбду:

v2.erase( std::remove_if(v2.begin(), v2.end(), [](auto&& x){ return !::is_odd(x); }), v2.end() );

Использование лямбда-функции или функционального объекта с inline Оператор вызова функции также имеет преимущество в том, что компилятору легче вставлять код.

Очевидно, что если вам нужно использовать C ++ до C ++ 11, std::not1/std::ptr_fun подход является самым простым для немедленного использования, а использование лямбда-функции даже невозможно. В этом случае вы можете создать простой объект функции для поддержки встраивания:

struct not_odd {
template <typename T>
bool operator()(T const& value) const { return !::odd(value); }
};
// ...
v2.erase( std::remove_if(v2.begin(), v2.end(), not_odd()), v2.end() );
5

По вопросам рекламы [email protected]