Предпочтительное стандартное использование: диапазон на основе или std :: for_each

В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-алгорифмов.

 Jerry Coffin03 апр. 2012 г., 16:27
Просто запомни этоfor_each (и на основе диапазона, как это), как правило, должен быть вашимпрошлой выбор алгоритмов. Обычно, что-то более специализированное для поставленной задачи будет лучшим выбором.
 Potatoswatter03 апр. 2012 г., 15:57
Мне интересно, как на самом деле правильноиспользование на основе диапазона, поэтому, пожалуйста, смотрите мой вопросstackoverflow.com/questions/9994789/...
 stefaanv03 апр. 2012 г., 16:49
@JerryCoffin: на самом деле последний, но один, есть еще классика для (;;), если все остальное не удается ...
 juanchopanza03 апр. 2012 г., 16:09
Я добавил простойfor_each пример. Я думал, что видел сообщение с просьбой об этом, но я не уверен больше ...
 stefaanv03 апр. 2012 г., 16:13
@juanchopanza: я попросил один, основанный на лямбде, но я удалил его, потому что во время публикации комментария я прочитал комментарий Potatoswatter о том, что запрос лямбды невозможен. Тем не менее, это хороший пример того, где for_each может быть лучше.

Ответы на вопрос(2)

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";
}
 Matthieu M.03 апр. 2012 г., 16:24
@juanchopanza: Действительно, к счастью, ситуация здесь улучшилась по сравнению с C ++ 03. В C ++ 03 было не указано, если вы получите полный результат (из-за копий), в то время как в C ++ 11 используются только операции перемещения.
 Potatoswatter03 апр. 2012 г., 15:49
+1, но обратите внимание, что в любом случае нет способа запросить лямбда-функтор; получение вспомогательного состояния будет осуществляться через переменную захвата, которая будет работать одинаково в любой конструкции.
 juanchopanza03 апр. 2012 г., 15:52
@Potatoswatter Хороший вопрос. Или путем создания объекта функции из лямбды.
Решение Вопроса

for очевидно проще читать и писать. Он специализирован для этой задачи.

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

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

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

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

 Matthieu M.03 апр. 2012 г., 16:21
@juanchopanza: конечно, если вы используетеRange контейнер (такой какBoost.Range), то это преимущество является спорным.
 juanchopanza03 апр. 2012 г., 15:53
+1 действительно, тот факт, что вы можете выбрать диапазон вfor_each очень мощный.
 Darrel Hoffman22 мар. 2016 г., 17:27
Одна из причин, по которой я бы предпочелfor черезstd::for_each это (по крайней мере, в VS2013, который я использую на работе),for_each метод не может быть легко отлажен. Вы можете установить точку останова в середине тела цикла, но она никогда не сработает. С дальнимforточки останова будут работать, как и ожидалось, при отладке.
 Klaim03 апр. 2012 г., 17:22
Возможно, вы захотите добавить это только для диапазона, чтобы разрешить разрыв и продолжить.
 James McNellis04 апр. 2012 г., 06:19
@Klaim:for_each опорыcontinue черезreturn из лямбды (или функции, или функтора). Заbreakподобное поведение, можно использоватьfind_if или другой более подходящий алгоритм.

Ваш ответ на вопрос