我发现我编写的很多代码都遵循"循环遍历此容器的模式,并对符合某些条件的元素执行X"。
通常看起来像这样:
std::vector<int> theList(10);
std::iota(theList.begin(), theList.end(), 0);
for (auto i : theList)
{
if ((i % 2) == 0)
{
//Do something with i
}
}
在这些情况下,我不喜欢if
语句 - 它们很丑陋并且会减损循环逻辑中真正发生的事情。
我喜欢的是一种更好的方法,因此很好地表达了问题的核心。
到目前为止,我最好的尝试并不是那么好:
std::vector<int> theList(10);
std::iota(theList.begin(), theList.end(), 0);
auto criteria = [](const int& i) -> bool { return (i % 2) == 0; };
for (auto it = std::find_if(theList.begin(), theList.end(), criteria);
it != theList.end();
it = std::find_if(++it, theList.end(), criteria)
)
{
std::cout << *it << ", ";
}
感觉这种模式应该以更清洁的方式进入std::algorithm
。
有更好的方法吗?
答案 0 :(得分:1)
您可以为此创建一个简单的高阶函数:
template <typename Range, typename Predicate, typename F>
void for_items_matching(Range&& r, Predicate&& p, F&& f)
{
for(auto&& x : r)
{
if(p(x)) { f(x); }
}
}
用法示例:
auto criteria = [](const int& i) -> bool { return (i % 2) == 0; };
for_items_matching(theList, criteria, [](auto&& item)
{
std::cout << item << ", ";
})
通过一些重构和辅助类/函数,你可能会得到类似的结果:
for_items_of(theList)
.matching(criteria)
.execute([](auto&& item){ std::cout << item << ", "; });
另一种可能性是查看即将到来的Ranges TS。
答案 1 :(得分:1)
如果我理解正确,那么您需要的是标准算法std::for_each_if
。例如
#include <iostream>
#include <iterator>
#include <numeric>
template<class InputIterator, class Predicate, class Function>
Function for_each_if(InputIterator first,
InputIterator last,
Predicate predicate,
Function f)
{
for (; first != last; ++first)
{
if (predicate(*first)) f(*first);
}
return f;
}
int main()
{
int a[10];
std::iota(std::begin(a), std::end(a), 0);
for_each_if(std::begin(a), std::end(a),
[](int x) { return x % 2 == 0; },
[](int x) { std::cout << x << ", "; });
std::cout << std::endl;
return 0;
}
程序输出
0, 2, 4, 6, 8,
然而实际上在C ++中没有这样的标准算法,尽管我建议将它包含在标准中。:)