6

我有代码从 astd::vector<int>中删除所有小于 some的元素int limit。我编写了一些部分应用 lambda 的函数:

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

auto less_than_three = less_than_limit(3);

当我用 测试它时std::vector<int> v{1,2,3,4,5};,我得到了预期的结果:

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

我可以轻松删除所有少于三个的元素:

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

如何使用删除大于或等于 3 的元素less_than_three

我尝试换行less_than_threestd::not1但出现错误:

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

然后我尝试std::not1(std::ref(less_than_three))了,但得到了这些错误:

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

如何在std::remove_if不更改 lambda 逻辑的情况下否定函数?换句话说,我该如何模仿remove_unless

4

4 回答 4

11

not1有点过时(并且要求函子提供某些成员 typedef,而 lambda 显然没有)。

你必须自己写一个否定器:

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

演示

于 2016-01-12T18:04:37.330 回答
7

std::not1假设您的函数对象将派生自std::unary_function,或至少提供相同的接口,因此它将具有result_type和的类型定义argument_type

由于 lambda 不会定义这些,因此您将无法not1在它们上使用。

显而易见的选择是创建与您自己相似的not1东西,但使用更现代的技术从它修改的任何内容中检测/传递参数/结果类型。

如果你真的想使用not1,那么最明智的方法是进行比较std::lessstd::bind指定要比较的值(即,它基本上是 C++03 的东西,所以如果你要去要使用它,您可以按照 C++03 的风格编写所有内容)。

于 2016-01-12T18:04:22.607 回答
4

您还可以使用 std::function 定义 lambda 的返回类型。

auto remove_gte_three = std::remove_if(std::begin(v), std::end(v), std::not1(std::function<int(int)>(less_than_three)));
于 2016-01-12T18:07:39.020 回答
1

not1() 否定器的旧方法(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));

使用 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());
}

用法:

keep_if(v, less_than_three);

或更通用的解决方案(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); });
}

用法:

auto p = remove_if_not(begin(v), end(v), less_than_three);
v.erase(p, v.end());
// Result: 1 2
于 2016-01-12T19:26:46.637 回答