I'm trying to write an in-place filter function that works similarly to Python's filter. For example:
std::vector<int> x = {1, 2, 3, 4, 5};
filter_ip(x, [](const int& i) { return i >= 3; });
// x is now {3, 4, 5}
First I tried this:
template <typename Container, typename Filter>
void filter_ip(Container& c, Filter&& f)
{
c.erase(std::remove_if(c.begin(), c.end(), std::not1(f)), c.end());
}
However, that doesn't work because lambdas don't have an argument_type field.
This following variant does work:
template <typename Container, typename Filter>
void filter_ip(Container& c, Filter&& f)
{
c.erase(std::remove_if(c.begin(), c.end(),
[&f](const typename Container::value_type& x) {
return !f(x);
}),
c.end());
}
However, it seems less than ideal because before, it would only have required that Container have begin, end, and erase, while now it also requires that it defines a value_type. Plus it looks a little unwieldy.
This is the 2nd approach in this answer. The first would use std::not1(std::function<bool(const typename Container::value_type&)>(f)) instead of the lambda, which still requires the type.
I also tried specifying the arg func as an std::function with a known argument type:
template <typename Container, typename Arg>
void filter_ip(Container& c, std::function<bool(const Arg&)>&& f)
{
c.erase(std::remove_if(c.begin(), c.end(), std::not1(f)), c.end());
}
But then I get:
'main()::<lambda(const int&)>' is not derived from 'std::function<bool(const Arg&)>'
Is there any way around this? Intuitively it seems it should be really simple since all you need to do is apply a not to a bool which you already know f returns.
If you can't use C++14 generic lambdas, how about delegating to a classic functor with a templated operator() :
#include <utility>
#include <vector>
#include <algorithm>
#include <iostream>
template <class F>
struct negate {
negate(F&& f)
: _f(std::forward<F>(f)) {}
template <class... Args>
bool operator () (Args &&... args) {
return !_f(std::forward<Args>(args)...);
}
private:
F _f;
};
template <typename Container, typename Filter>
void filter_ip(Container& c, Filter&& f)
{
c.erase(std::remove_if(
c.begin(),
c.end(),
negate<Filter>(std::forward<Filter>(f))),
c.end()
);
}
int main() {
std::vector<int> v {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
filter_ip(v, [](int i) {return bool(i%2);});
for(auto &&i : v)
std::cout << i << ' ';
std::cout << '\n';
}
Output :
1 3 5 7 9
Live on Coliru
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With