在擦除 - 删除习语中使用UnaryPredicate的否定

时间:2015-12-17 08:37:07

标签: c++ c++03 erase-remove-idiom

考虑以下情况:

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);  
}

2 个答案:

答案 0 :(得分:9)

检查std::not1功能。它做你想要的。

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

Live example

无论如何,如果由我自己加上C ++ 11可用,我会优先考虑:

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

因为我记得std::not1lambda可用之前有所帮助。

答案 1 :(得分:5)

您可以使用std::not1。遗憾的是,std::not1需要一个具有嵌套argument_typeresult_type类型的函数对象参数。也就是说,它不能直接使用。相反,当使用带有正常函数的negator时,有必要将使用与std::ptr_fun结合使用:

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

在上一次委员会会议上,std::not_fn已从Library Fundamentals TS 2移至工作草案。也就是说,希望使用C ++ 17可以更好地提供通用的否定器。

通常,当您需要使用任何std::*_fun函数时,乐趣就会停止。正如其他人所指出的那样,使用lambda可能是合理的:

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

使用lambda函数或带有inline函数调用操作符的函数对象也具有编译器更容易内联代码的优势。

显然,如果你需要在C ++ 11之前使用C ++,std::not1 / std::ptr_fun方法是最容易立即使用的方法,甚至不可能使用lambda函数。在这种情况下,您可能想要创建一个简单的函数对象来支持内联:

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() );