Подтвердить что ты не робот

Предпочтительное стандартное использование: диапазон, основанный на или 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 -алгоритмы.

4b9b3361

Ответ 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";
}