mardi 2 juin 2015

Negate a lambda without knowing the argument type?

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.

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.

Aucun commentaire:

Enregistrer un commentaire