2012-04-03 9 views
36

En C++11, hay dos bucles en todos los elementos (rango basado en y para_cada). ¿Hay alguna razón para preferir una sobre otra o hay situaciones en las que uno se ajusta mejor?Uso estándar preferido: rango basado en o std :: for_each

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

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

Mi idea sería que la primera es más simple y es similar a variar bucles basados ​​en otros idiomas, mientras que la segunda también trabaja para las secuencias que no son contenedores completos y el segundo es más similar a otros std -algorithms.

+0

Tengo curiosidad acerca de la manera de uso * * gama-basa para, así que por favor ver realmente mi pregunta correctamente http://stackoverflow.com/questions/9994789/proper-style-for-declaration-in -range-based-for – Potatoswatter

+0

Agregué un simple ejemplo 'for_each'. Pensé que había visto un mensaje pidiéndome uno, pero ya no estoy tan seguro ... – juanchopanza

+0

@juanchopanza: Pedí uno basado en el lambda, pero lo eliminé porque en el momento en que publiqué el comentario, lee el comentario de Potatoswatter de que consultar a un lambda no fue posible. Aún así, es un buen ejemplo de dónde podría ser mejor para cada uno. – stefaanv

Respuesta

26
  1. Rango for es obviamente más fácil de leer y escribir. Está especializado para esta tarea.

    EDITAR: Puede romper un rango sin abusar de una excepción. (Aunque std::find_if sustituido por std::for_each permite esto también.)

  2. std::for_each, irónicamente, es la alternativa que es en realidad intervalo basado y le permite seleccionar particulares begin y end valores en lugar de todo el contenedor. (EDIT: Esto puede ser pirateado alrededor de usar un simple clase range proporcionar begin y end miembros, tales como los proporcionados por Boost.)

    También for_each puede haber más elegante cuando de otro modo el uso de funciones de orden superior: se puede utilizar como argumento al bind, y el tercer argumento ya es un funtor.

Principalmente es una cuestión de estilo. La mayoría de los lectores probablemente prefiera ver for (auto &a : b), y la mayoría de las implementaciones ahora lo admiten.

+0

+1 de hecho, el hecho de que pueda elegir el rango en 'for_each' es muy poderoso. – juanchopanza

+5

@juanchopanza: por supuesto, si usas un contenedor 'Range '(como' Boost.Range'), entonces esta ventaja es discutible. –

+5

Es posible que desee agregar ese único rango, para permitir el descanso y continuar. – Klaim

10

std::for_each devuelve el functor que se ha utilizado internamente en el bucle, por lo que proporciona un mecanismo de limpieza para recopilar cierta información sobre los elementos de la secuencia. El rango basado en el bucle es solo un bucle, por lo que cualquier estado que se use fuera del bucle debe declararse fuera de ese alcance. En su ejemplo, si el propósito de los bucles es mutar cada elemento de la secuencia, entonces no hay mucha diferencia. Pero si no está utilizando el valor de retorno del for_each, entonces probablemente esté mejor con el bucle simple. Por cierto, el bucle basado en rango también funciona en arreglos tipo C y std :: strings.

Este es un ejemplo del uso del valor de retorno de for_each, aunque no es muy imaginativo ni útil. Es solo para ilustrar la idea.

#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"; 
} 
+1

+1, pero tenga en cuenta que no hay manera de consultar un functor lambda de todos modos; la obtención del estado auxiliar se haría a través de una variable de captura, que funcionaría igual en cualquiera de los constructos. – Potatoswatter

+0

@Potatoswatter Buen punto. O creando un objeto de función de la lambda. – juanchopanza

+2

@juanchopanza: De hecho, la situación afortunadamente mejoró también en C++ 03. En C++ 03 no se especificó si obtendría un resultado completo (debido a las copias), mientras que en C++ 11 solo se usan operaciones de movimiento. –

Cuestiones relacionadas