¿Cuál de los siguientes le parece más legible? El bucle escrito a mano:
for (std::vector<Foo>::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
bar.process(*it);
}
O la invocación del algoritmo:
#include <algorithm>
#include <functional>
std::for_each(vec.begin(), vec.end(),
std::bind1st(std::mem_fun_ref(&Bar::process), bar));
Me pregunto si std::for_each
realmente vale la pena, dado que un ejemplo tan simple ya requiere mucho código.
¿Qué piensas sobre este asunto?
c++
algorithms
flujo libre
fuente
fuente
map(bar.process, vec)
aunque se desaconseja el mapa de efectos secundarios y se recomiendan las comprensiones de lista / expresiones generadoras sobre el mapa).BOOST_FOREACH
...Respuestas:
Hay una razón por la que se introdujeron las lambdas, y es porque incluso el Comité Estándar reconoce que la segunda forma apesta. Use la primera forma, hasta que obtenga soporte para C ++ 0x y lambda.
fuente
Utilice siempre la variante que describe mejor lo que pretende hacer. Es decir
Ahora, examinemos los ejemplos:
También tenemos una
for_each
, sí, sí . Tenemos el[begin; end)
rango en el que queremos operar.En principio, el algoritmo era mucho más explícito y, por lo tanto, preferible a cualquier implementación escrita a mano. Pero entonces ... Binders? Memfun? Básicamente C ++ interna de cómo obtener una función miembro? ¡Para mi tarea, no me importan ! Tampoco quiero sufrir esta sintaxis verbosa y espeluznante.
Ahora la otra posibilidad:
Por supuesto, este es un patrón común para reconocer, pero ... creando iteradores, bucles, incrementos, desreferenciación. Estas también son cosas que no me importan para poder hacer mi tarea.
Es cierto que se ve mucho mejor que la primera solución (al menos, el cuerpo del bucle es flexible y bastante explícito), pero aún así, no es realmente tan bueno. Usaremos este si no tuviéramos una mejor posibilidad, pero tal vez tengamos ...
¿Una mejor manera?
Ahora de vuelta a
for_each
. ¿No sería genial decir literalmentefor_each
y ser flexible en la operación que también se debe hacer? Afortunadamente, desde C ++ 0x lambdas, somosAhora que hemos encontrado una solución abstracta y genérica para muchas situaciones relacionadas, vale la pena señalar que en este caso particular, hay un favorito absoluto # 1 :
Realmente no puede ser mucho más claro que eso. Afortunadamente, C ++ 0x get tiene una sintaxis similar incorporada .
fuente
for (const Foo& x : vec) bar.process(x);
, o usaconst auto&
si lo desea.const auto&
¿es posible? No lo sabía, ¡gran información!¿Porque esto es tan ilegible?
fuente
int
con unsize_t
es peligroso. Además, la indexación no funciona con todos los contenedores, por ejemplostd::set
.en general, la primera forma es legible por cualquiera que sepa lo que es un bucle for, sin importar el fondo que tengan.
También en general, el segundo no es tan fácil de leer: es bastante fácil imaginar qué está haciendo for_each, pero si nunca lo has visto
std::bind1st(std::mem_fun_ref
, puedo imaginar que es difícil de entender.fuente
En realidad, incluso con C ++ 0x, no estoy seguro de
for_each
que reciba mucho amor.Es mucho más legible.
Lo único que no me gusta de los algoritmos (en C ++) es que razonan en iteradores, lo que hace declaraciones muy detalladas.
fuente
Si hubiera escrito bar como functor, entonces sería mucho más simple:
Aquí el código es bastante legible.
fuente
Prefiero el último porque está limpio y ordenado. En realidad, es parte de muchos otros lenguajes, pero en C ++, es parte de la biblioteca. Realmente no importa.
fuente
Ahora, este problema en realidad no es específico de C ++, diría.
La cuestión es que pasar algún functor a otra función más no pretende reemplazar los bucles .
Se supone que simplifica ciertos patrones, que se vuelven muy naturales con la programación funcional, como visitante y observador , solo por nombrar dos, que vienen a mi mente de inmediato.
En lenguajes que carecen de funciones de primer orden (Java probablemente es el mejor ejemplo), tales enfoques siempre requieren implementar alguna interfaz dada, que es bastante verbosa y redundante.
Un uso común que veo mucho en otros idiomas sería:
La ventaja de esto es que no necesita saber cómo
someCollection
se implementa realmente o quésomeUnaryFunctor
hace. Todo lo que necesita saber es que suforEach
método iterará todos los elementos de la colección, pasándolos a la función dada.Personalmente, si está en la posición de tener toda la información sobre la estructura de datos sobre la que desea iterar y toda la información sobre lo que desea hacer en cada paso de iteración, entonces un enfoque funcional es complicar las cosas, especialmente en un lenguaje, donde esto es aparentemente bastante tedioso.
Además, debe tener en cuenta que el enfoque funcional es más lento, porque tiene muchas llamadas, que tienen un costo determinado, que no tiene en un bucle for.
fuente
std::for_each(vec.begin(), vec.end(), std::bind1st(std::mem_fun_ref(&Bar::process), bar));
Y es más lento en tiempo de ejecución o tiempo de compilación (si tienes suerte). No veo por qué reemplazar las estructuras de control de flujo con llamadas a funciones mejora el código. Sobre cualquier alternativa presentada aquí es más legible.Creo que el problema aquí es que
for_each
no es realmente un algoritmo, es solo una forma diferente (y generalmente inferior) de escribir un bucle escrito a mano. desde esta perspectiva, debería ser el algoritmo estándar menos utilizado, y sí, probablemente también debería usar un bucle for. sin embargo, el consejo en el título sigue en pie, ya que hay varios algoritmos estándar diseñados para usos más específicos.Donde hay un algoritmo que hace más estrictamente lo que quiere, entonces sí, debería preferir algoritmos a loops escritos a mano. ejemplos obvios aquí son ordenar con
sort
ostable_sort
buscar conlower_bound
,upper_bound
oequal_range
, pero la mayoría de ellos tienen alguna situación en la que es preferible usarlos en un bucle codificado a mano.fuente
Para este pequeño fragmento de código, ambos son igualmente legibles para mí. En general, encuentro bucles manuales propensos a errores y prefiero usar algoritmos, pero realmente depende de una situación concreta.
fuente