Предпочтительное стандартное использование: диапазон, основанный на или std:: for_each
В С++ 11 существует два цикла по всем элементам (диапазон основан для and for_each). Есть ли какая-то причина предпочитать одну над другой или есть ситуации, когда лучше подходит?
for (auto& elem: container) {
// do something with elem
}
std::for_each(container.begin(), container.end(),
[](Elem& elem) {
// do something with elem
});
Моя идея была бы в том, что первая проще и похожа на циклы, основанные на диапазонах, на других языках, а вторая также работает на последовательности, которые не являются полными контейнерами, а вторая больше похожа на другие std
-алгоритмы.
Ответы
Ответ 1
-
На основе for
на основе диапазона, очевидно, проще читать и писать. Он специализирован для этой задачи.
РЕДАКТИРОВАТЬ: Вы можете разбить форму диапазона, не злоупотребляя исключением. (Хотя std::find_if
, замененный на std::for_each
, позволяет это также.)
-
std::for_each
, по иронии судьбы, является альтернативой, которая фактически основана на диапазоне и позволяет вам выбирать конкретные значения begin
и end
вместо всего контейнера. ( EDIT:. Это можно взломать с помощью простого класса range
, предоставляющего члены begin
и end
, например, предоставленные Boost.)
Также for_each
может быть более изящным, если в противном случае использовать функции более высокого порядка: его можно использовать в качестве аргумента для bind
, а третий аргумент уже является функтором.
В основном это вопрос стиля. Большинство читателей, вероятно, предпочитают видеть for ( auto &a : b )
, хотя большинство реализаций теперь поддерживают его.
Ответ 2
std::for_each
возвращает функтор, который использовался внутри цикла, поэтому он обеспечивает чистый механизм для сбора некоторой информации о элементах в последовательности. Диапазон, основанный на цикле, представляет собой всего лишь цикл, поэтому любое состояние, которое должно использоваться вне цикла, должно быть объявлено вне этой области. В вашем примере, если цель цикла состоит в том, чтобы мутировать каждый элемент последовательности, то нет никакой разницы. Но если вы не используете возвращаемое значение for_each
, тогда вам, вероятно, будет лучше с простым циклом. Кстати, петля на основе диапазона работает и с массивами в стиле С и std:: string.
Это пример использования возвращаемого значения 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";
}