How to emulate remove_unless

I have code to remove all elements from std::vector<int> that are less than some int limit . I wrote some functions that partially use lambdas:

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

When I test it with std::vector<int> v{1,2,3,4,5}; I get the expected results:

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

I can easily remove all elements of less than three:

 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 

How to remove items that are greater than or equal to 3 using less_than_three ?

I tried wrapping less_than_three in std::not1 , but got errors:

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

Then I tried std::not1(std::ref(less_than_three)) , but got the following errors:

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

How can I negate a function in std::remove_if without changing the logic of my lambdas? In other words, how can I emulate remove_unless ?

+6
source share
4 answers

std::not1 assumes your function object will be derived from std::unary_function or at least provide the same interface, so it will have a typedef for result_type and argument_type .

Since lambda will not define them, you cannot use not1 for them.

The obvious choice would be to create something similar to not1 yourself, but using more modern methods to detect / pass through the argument / type of the result from what it changes.

If you really want to use not1 , then the most reasonable approach would be to compare with std::less and std::bind to indicate the value you are going to compare with (i.e. basically this is C ++ 03, so if you are going to use it, you write everything in C ++ style 03).

+7
source

not1 somewhat outdated (and requires the functor to provide specific typedefs that the lambda does not explicitly do).

You will need to write the negator yourself:

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

Demo

+11
source

You can also determine the return type of a lambda using 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
source

Old way with not1 () negator (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)); 

New way with lambda (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()); } 

Using:

 keep_if(v, less_than_three); 

Or a more general solution (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); }); } 

Using:

 auto p = remove_if_not(begin(v), end(v), less_than_three); v.erase(p, v.end()); // Result: 1 2 
+1
source

All Articles