如何模拟 remove_unless
How to emulate remove_unless
我有代码可以从 std::vector<int>
中删除小于某些 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
如何使用 less_than_three
删除大于或等于 3 的元素?
我尝试将 less_than_three
包装在 std::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)); }
^
如何在不改变我的 lambda 逻辑的情况下取反 std::remove_if
中的函数?换句话说,我如何模拟 remove_unless
?
std::not1
假定您的函数对象将从 std::unary_function
派生,或者至少提供相同的接口,因此它将具有 result_type
和 argument_type
的类型定义。
由于 lambda 不会定义它们,您将无法对它们使用 not1
。
显而易见的选择是自己创建类似于 not1
的东西,但使用更现代的技术 detect/pass 通过 argument/result 类型从它修改的任何内容。
如果您真的想使用 not1
,那么最明智的方法是与 std::less
和 std::bind
进行比较,以指定您要达到的值比较(即,它基本上是 C++03 的东西,所以如果你要使用它,你可以按照 C++03 的风格编写所有内容)。
not1
有点过时(并且要求仿函数提供某些成员类型定义,而 lambda 显然不提供)。
你必须自己写一个否定符:
auto negate = [] (auto&& f) {return [f=std::forward<decltype(f)>(f)]
(auto&&... args) {return !f(std::forward<decltype(args)>(args)...);};};
Demo.
您还可以使用 std::function 定义 lambda 的 return 类型。
auto remove_gte_three = std::remove_if(std::begin(v), std::end(v), std::not1(std::function<int(int)>(less_than_three)));
使用 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
我有代码可以从 std::vector<int>
中删除小于某些 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
如何使用 less_than_three
删除大于或等于 3 的元素?
我尝试将 less_than_three
包装在 std::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)); }
^
如何在不改变我的 lambda 逻辑的情况下取反 std::remove_if
中的函数?换句话说,我如何模拟 remove_unless
?
std::not1
假定您的函数对象将从 std::unary_function
派生,或者至少提供相同的接口,因此它将具有 result_type
和 argument_type
的类型定义。
由于 lambda 不会定义它们,您将无法对它们使用 not1
。
显而易见的选择是自己创建类似于 not1
的东西,但使用更现代的技术 detect/pass 通过 argument/result 类型从它修改的任何内容。
如果您真的想使用 not1
,那么最明智的方法是与 std::less
和 std::bind
进行比较,以指定您要达到的值比较(即,它基本上是 C++03 的东西,所以如果你要使用它,你可以按照 C++03 的风格编写所有内容)。
not1
有点过时(并且要求仿函数提供某些成员类型定义,而 lambda 显然不提供)。
你必须自己写一个否定符:
auto negate = [] (auto&& f) {return [f=std::forward<decltype(f)>(f)]
(auto&&... args) {return !f(std::forward<decltype(args)>(args)...);};};
Demo.
您还可以使用 std::function 定义 lambda 的 return 类型。
auto remove_gte_three = std::remove_if(std::begin(v), std::end(v), std::not1(std::function<int(int)>(less_than_three)));
使用 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