Предпочтительное стандартное использование: диапазон на основе или std :: for_each - PullRequest
46 голосов
/ 03 апреля 2012

В C ++ 11 есть два цикла для всех элементов (диапазон основан на и for_each).Есть ли какая-либо причина, чтобы предпочесть один другому, или есть ситуации, когда один лучше подходит?

for (auto& elem: container) {
  // do something with elem
}

std::for_each(container.begin(), container.end(),
              [](Elem& elem) {
                // do something with elem
              });

Моя идея состоит в том, что первое проще и похоже на циклы на основе диапазона в других языках, в то время каквторая также работает для последовательностей, которые не являются полными контейнерами, а вторая больше похожа на другие std -алгоритмы.

Ответы [ 2 ]

32 голосов
/ 03 апреля 2012
  1. На основе диапазона for очевидно проще для чтения и записи. Он специализирован для этой задачи.

    РЕДАКТИРОВАТЬ: Вы можете разбить диапазон для без злоупотребления исключением. (Хотя std::find_if вместо std::for_each также позволяет это.)

  2. std::for_each, по иронии судьбы, является альтернативой, которая фактически основана на диапазоне и позволяет выбирать конкретные значения begin и end вместо всего контейнера. ( РЕДАКТИРОВАТЬ: Это можно взломать с помощью простого класса range, предоставляющего begin и end членов, таких как предоставляемые Boost.)

    Также for_each может быть более элегантным при использовании функций высшего порядка: его можно использовать в качестве аргумента для bind, а третий аргумент уже является функтором.

В основном это вопрос стиля. Большинство читателей, вероятно, предпочитают видеть for ( auto &a : b ), и большинство реализаций теперь поддерживают его.

11 голосов
/ 03 апреля 2012

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