首选标准用法:基于范围的 for 或 std::for_each

问题描述 投票:0回答:3

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.

c++ coding-style c++11
3个回答
42
投票
  1. Range-based

    for
    显然更易于读写。它专门用于此任务。

    编辑: 您可以在不滥用异常的情况下打破范围。 (虽然

    std::find_if
    代替
    std::for_each
    也允许这样做。)

  2. 具有讽刺意味的是,
  3. std::for_each
    是替代方案,它实际上是基于范围的,允许您选择特定的
    begin
    end
    值,而不是整个容器。 (编辑: 这可以使用简单的
    range
    类来解决,提供
    begin
    end
    成员,例如 Boost 提供的。)

    另外

    for_each
    在使用高阶函数时可能更优雅:它可以用作
    bind
    的参数,第三个参数已经是一个函子。

主要是风格问题。不过,大多数读者可能更喜欢看到

for ( auto &a : b )
,现在大多数实现都支持它。


17
投票

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";
}

0
投票

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 做同样的事情。

© www.soinside.com 2019 - 2024. All rights reserved.