In C++11, there are two loops over all elements (range based for and for_each). Is there any reason to prefer one over the other or are there situations where one is a better fit?
在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
});
My idea would be that the first is simpler and is similar to range based loops in other languages while the second also works for sequences that are not complete containers and the second is more similar to other std
-algorithms.
我的想法是,第一个更简单,类似于其他语言中的基于范围的循环,而第二个也适用于不完整容器的序列,第二个更类似于其他的标准-算法。
2 个解决方案
#1
27
-
Range-based
for
is obviously simpler to read and write. It is specialized for this task.基于范围的for显然更容易读和写。它专门用于这项任务。
EDIT: You can break form a range-for without abusing an exception. (Although
std::find_if
substituted forstd::for_each
allows this as well.)编辑:你可以在不滥用异常的情况下打破范围。(虽然用std::find_if替换std::for_each也允许这样)
-
std::for_each
, ironically, is the alternative which is actually range based and allows you to select particularbegin
andend
values instead of the whole container. (EDIT: This can be hacked around using a simplerange
class providingbegin
andend
members, such as provided by Boost.)具有讽刺意味的是,for_each实际上是基于范围的替代方法,允许您选择特定的开始和结束值,而不是整个容器。(编辑:可以使用一个简单的范围类,提供开始和结束成员,如Boost提供的)。
Also
for_each
may be more elegant when otherwise using higher-order functions: it can be used as an argument tobind
, and the third argument is already a functor.for_each在使用高阶函数时可能更优雅:它可以用作绑定的参数,第三个参数已经是一个函数。
Mainly it's a matter of style. Most readers probably prefer to see for ( auto &a : b )
though, and most implementations now support it.
主要是风格的问题。大多数读者可能更喜欢看(auto & &a: b),而且大多数实现现在都支持它。
#2
11
std::for_each
returns the functor that has been used internally in the loop, so it provides a clean mechanism to gather some information concerning the elements in the sequence. The range based for loop is just a loop, so any state that is to be used outside of the loop has to be declared outside of that scope. In your example, if the purpose of the of the loops is to mutate each element of the sequence, then there isn't much difference at all. But if you are not using the return value of the for_each
then you're probably better off with the simple loop. By the way, the range based loop works on C-style arrays and std::strings too.
for_each返回循环内部使用的函子,因此它提供了一个干净的机制来收集关于序列中的元素的一些信息。基于循环的范围只是一个循环,因此,在循环之外使用的任何状态都必须在该范围之外声明。在您的示例中,如果循环的目的是使序列中的每个元素发生突变,那么根本没有什么区别。但是如果不使用for_each的返回值,那么最好使用简单的循环。顺便说一下,基于范围的循环也适用于c风格的数组和std::string。
This is an example of using the return value of for_each
, although it is not a very imaginative or useful one. It is just to illustrate the idea.
这是一个使用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";
}
#1
27
-
Range-based
for
is obviously simpler to read and write. It is specialized for this task.基于范围的for显然更容易读和写。它专门用于这项任务。
EDIT: You can break form a range-for without abusing an exception. (Although
std::find_if
substituted forstd::for_each
allows this as well.)编辑:你可以在不滥用异常的情况下打破范围。(虽然用std::find_if替换std::for_each也允许这样)
-
std::for_each
, ironically, is the alternative which is actually range based and allows you to select particularbegin
andend
values instead of the whole container. (EDIT: This can be hacked around using a simplerange
class providingbegin
andend
members, such as provided by Boost.)具有讽刺意味的是,for_each实际上是基于范围的替代方法,允许您选择特定的开始和结束值,而不是整个容器。(编辑:可以使用一个简单的范围类,提供开始和结束成员,如Boost提供的)。
Also
for_each
may be more elegant when otherwise using higher-order functions: it can be used as an argument tobind
, and the third argument is already a functor.for_each在使用高阶函数时可能更优雅:它可以用作绑定的参数,第三个参数已经是一个函数。
Mainly it's a matter of style. Most readers probably prefer to see for ( auto &a : b )
though, and most implementations now support it.
主要是风格的问题。大多数读者可能更喜欢看(auto & &a: b),而且大多数实现现在都支持它。
#2
11
std::for_each
returns the functor that has been used internally in the loop, so it provides a clean mechanism to gather some information concerning the elements in the sequence. The range based for loop is just a loop, so any state that is to be used outside of the loop has to be declared outside of that scope. In your example, if the purpose of the of the loops is to mutate each element of the sequence, then there isn't much difference at all. But if you are not using the return value of the for_each
then you're probably better off with the simple loop. By the way, the range based loop works on C-style arrays and std::strings too.
for_each返回循环内部使用的函子,因此它提供了一个干净的机制来收集关于序列中的元素的一些信息。基于循环的范围只是一个循环,因此,在循环之外使用的任何状态都必须在该范围之外声明。在您的示例中,如果循环的目的是使序列中的每个元素发生突变,那么根本没有什么区别。但是如果不使用for_each的返回值,那么最好使用简单的循环。顺便说一下,基于范围的循环也适用于c风格的数组和std::string。
This is an example of using the return value of for_each
, although it is not a very imaginative or useful one. It is just to illustrate the idea.
这是一个使用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";
}