在C++11中,所有元素都有两个循环(基于范围的for和for_each)。有什么理由比另一个更喜欢一个,或者在某些情况下一个更合适?
for (auto& elem: container) {
// do something with elem
}
std::for_each(container.begin(), container.end(),
[](Elem& elem) {
// do something with elem
});
我的想法是第一个更简单,类似于其他语言中基于范围的循环,而第二个也适用于不完整容器的序列,第二个更类似于其他
std
-algorithms.
Range-based
for
显然更易于读写。它专门用于此任务。
编辑: 您可以在不滥用异常的情况下打破范围。 (虽然
std::find_if
代替 std::for_each
也允许这样做。)std::for_each
是替代方案,它实际上是基于范围的,允许您选择特定的 begin
和 end
值,而不是整个容器。 (编辑: 这可以使用简单的 range
类来解决,提供 begin
和 end
成员,例如 Boost 提供的。)
另外
for_each
在使用高阶函数时可能更优雅:它可以用作 bind
的参数,第三个参数已经是一个函子。主要是风格问题。不过,大多数读者可能更喜欢看到
for ( auto &a : b )
,现在大多数实现都支持它。
std::for_each
返回已在循环内部使用的仿函数,因此它提供了一种干净的机制来收集有关序列中元素的一些信息。基于范围的 for 循环只是一个循环,因此任何要在循环之外使用的状态都必须在该范围之外声明。在您的示例中,如果循环的目的是改变序列的每个元素,那么根本没有太大区别。但是,如果您不使用 for_each
的返回值,那么使用简单循环可能会更好。顺便说一句,基于范围的循环也适用于 C 风格的数组和 std::strings。
这是一个使用
for_each
的返回值的例子,虽然不是很有想象力和实用性的例子。这只是为了说明这个想法。
#include <iostream>
#include <array>
#include <algorithm>
struct Foo {
void operator()(int i) { if (i > 4) sum += i;}
int sum{0};
};
int main() {
std::array<int, 10> a{1,2,3,4,5,6,7,8,9,10};
Foo foo = std::for_each(a.begin(), a.end(), Foo());
std::cout << "Sum " << foo.sum << "\n";
}
C++17 起
std::for_each
还支持执行策略.
例如,通过写作
std::vector<int> v = {1, 2, 3};
std::for_each(std::execution::par, v.begin(), v.end(), [](int &n){ ++n; });
你告诉编译器循环可以并行化。你不能对基于范围的 for 做同样的事情。