在不知道参数类型的情况下否定lambda?

Cla*_*diu 3 c++ lambda templates types c++11

我正在尝试编写一个与Python的过滤器类似的就地过滤器功能.例如:

std::vector<int> x = {1, 2, 3, 4, 5};
filter_ip(x, [](const int& i) { return i >= 3; });
// x is now {3, 4, 5}
Run Code Online (Sandbox Code Playgroud)

首先我尝试了这个:

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());
}
Run Code Online (Sandbox Code Playgroud)

但是,这不起作用,因为lambdas 没有argument_type字段.

以下变体确实有效:

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());
}
Run Code Online (Sandbox Code Playgroud)

然而,似乎不太理想,因为之前,这将只会要求Containerbegin,enderase,而现在它也要求它定义了一个value_type.而且它看起来有点笨拙.

这是这个答案中的第二种方法.第一个将使用std::not1(std::function<bool(const typename Container::value_type&)>(f))而不是lambda,它仍然需要类型.

我还尝试将arg func指定为std::function具有已知参数类型的参数:

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());
}
Run Code Online (Sandbox Code Playgroud)

但后来我得到:

'main()::<lambda(const int&)>' is not derived from 'std::function<bool(const Arg&)>'
Run Code Online (Sandbox Code Playgroud)

有没有办法解决?直观地说它似乎应该非常简单,因为你需要做的就是将一个不应用于你已经知道f返回的bool .

Que*_*tin 5

如果你不能使用C++ 14泛型lambdas,那么如何委托一个带有模板化的经典仿函数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';
}
Run Code Online (Sandbox Code Playgroud)

输出:

1 3 5 7 9 
Run Code Online (Sandbox Code Playgroud)

住在Coliru

  • 推导出`operator()`的返回类型可能会更好,以允许通过SFINAE检测*是否可调用*.另外,`negate`可能不是最好的名字,因为`std :: negate`使用一元`-`(减号),而不是`!`(逻辑不). - 哦,习惯上为类型推导添加工厂函数模板. (2认同)