Using UnaryPredicate negation in erasing-removing idioms

Consider the following scenario:

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 it possible to use the same is_odd() UnaryPredicate to remove the even numbers as expected in the last line of main() . Or I will have to write a is_even() , although this will be nothing more than:

 bool is_even(int i) { !is_odd(i); } 
+5
source share
2 answers

check std :: not1 . he does what you want.

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

Real time example

In any case, if it depends on me plus C ++ 11, I would prefer:

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

since, as far as I remember, std::not1 was useful before lambda was available.

+9
source

You can use std::not1 . Unfortunately, std::not1 requires a function object argument with nested types argument_type and result_type . That is, it cannot be used directly. Instead, you must combine use with std::ptr_fun when using a std::ptr_fun with a normal function:

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

At the last committee meeting, std::not_fn was moved from the TS 2 Fundamentals Library to a working draft. That is, there is hope that with C ++ 17 there is a better suggestion for a common negator.

In general, the fun stops when you need to use any of the functions std::*_fun . As others have pointed out, it is advisable to use a lambda instead:

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

Using a lambda function or function object with an inline function call operator also has the advantage that the compiler has an easier time pasting the code.

Obviously, if you need to use C ++ before C ++ 11, then the std::not1 / std::ptr_fun is the easiest to use immediately, using a lambda function is not even possible. In this case, you may need to create a simple function object to support the attachment:

 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
source

Source: https://habr.com/ru/post/1238495/


All Articles