expresiones - std c++
¿Cuál es la motivación detrás de las expresiones C++ 11 lambda? (8)
Estoy tratando de averiguar si hay un beneficio computacional real para usar expresiones lambda en C ++, es decir, "este código se compila / ejecuta más rápido / más lento porque usamos expresiones lambda" o es solo una clara ventaja de desarrollo abierta para el abuso por codificadores pobres tratando de parecer genial?
Entiendo que esta pregunta puede parecer subjetiva, pero agradecería mucho la opinión de la comunidad sobre este asunto.
Bueno, compara esto:
int main () {
std::vector<int> x = {2, 3, 5, 7, 11, 13, 17, 19};
int center = 10;
std::sort(x.begin(), x.end(), [=](int x, int y) {
return abs(x - center) < abs(y - center);
});
std::for_each(x.begin(), x.end(), [](int v) {
printf("%d/n", v);
});
return 0;
}
con este:
// why enforce this to be defined nonlocally?
void printer(int v) {
printf("%d/n", v);
}
int main () {
std::vector<int> x = {2, 3, 5, 7, 11, 13, 17, 19};
// why enforce we to define a whole struct just need to maintain a state?
struct {
int center;
bool operator()(int x, int y) const {
return abs(x - center) < abs(y - center);
}
} comp = {10};
std::sort(x.begin(), x.end(), comp);
std::for_each(x.begin(), x.end(), printer);
return 0;
}
IMO, lo más importante sobre lambda es que mantiene el código relacionado muy cerca. Si tienes este código:
std::for_each(begin, end, unknown_function);
Necesita navegar a unknown_function
para entender lo que hace el código. Pero con una lambda, la lógica puede mantenerse junta.
Lambdas son azúcar sintáctico para las clases de functor, por lo que no, no hay beneficio computacional. En cuanto a la motivación, ¿probablemente alguna otra docena de lenguas populares que tienen lambdas en ellas?
Se podría argumentar que ayuda en la legibilidad del código (tener tu functor declarado en línea donde se usa).
No creo que sea tanto el rendimiento computacional como el aumento del poder expresivo del lenguaje.
No hay beneficio de rendimiento per se, pero la necesidad de lambda surgió como consecuencia de la amplia adopción de STL y sus ideas de diseño.
Específicamente, los algoritmos STL hacen uso frecuente de funtores. Sin lambda, estos funtores deben declararse previamente para ser utilizados. Lambdas hace posible tener funcionadores "anónimos" en el lugar.
Esto es importante porque hay muchas situaciones en las que necesita usar un functor solo una vez, y no desea darle un nombre por dos razones: no desea contaminar el espacio de nombres, y en esos casos específicos el nombre que das es vago o extremadamente largo.
Yo, por ejemplo, uso mucho STL, pero sin C ++ 0x utilizo mucho más para los bucles () que el algoritmo for_each () y sus primos. Eso es porque si tuviera que usar for_each () en su lugar, necesitaría obtener el código del circuito y declarar un functor para él. Además, no se podría acceder a todas las variables locales antes del bucle, así que necesitaría escribir código adicional para pasarlas como parámetros al constructor del functor u otra cosa equivalente. Como consecuencia, tiendo a no usar for_each () a menos que haya una gran motivación, de lo contrario el código sería más largo y más difícil de leer.
Eso es malo, porque es bien sabido que el uso de for_each () y algoritmos similares da mucho más espacio al compilador y la biblioteca para optimizaciones, incluido el paralelismo automático. Entonces, indirectamente, lambda favorecerá un código más eficiente.
"¿ una clara ventaja de desarrollo abierta para el abuso por codificadores pobres tratando de parecer genial? " ... como sea que lo llames, hace que el código sea mucho más legible y mantenible. No aumenta el rendimiento.
Muy a menudo, un programador itera sobre un rango de elementos (buscando un elemento, acumulando elementos, clasificando elementos, etc.). Usando el estilo funcional, inmediatamente verá lo que el programador intenta hacer, como diferente del uso de bucles for, donde todo "parece" lo mismo.
Comparar algoritmos + lambda:
iterator longest_tree = std::max_element(forest.begin(), forest.end(), [height]{arg0.height>arg1.height});
iterator first_leaf_tree = std::find_if(forest.begin(), forest.end(), []{is_leaf(arg0)});
std::transform(forest.begin(), forest.end(), firewood.begin(), []{arg0.trans(...));
std::for_each(forest.begin(), forest.end(), {arg0.make_plywood()});
con old-school for-loops;
Forest::iterator longest_tree = it.begin();
for (Forest::const_iterator it = forest.begin(); it != forest.end(); ++it{
if (*it.height() > *longest_tree.height()) {
longest_tree = it;
}
}
Forest::iterator leaf_tree = it.begin();
for (Forest::const_iterator it = forest.begin(); it != forest.end(); ++it{
if (it->type() == LEAF_TREE) {
leaf_tree = it;
break;
}
}
for (Forest::const_iterator it = forest.begin(), jt = firewood.begin();
it != forest.end();
it++, jt++) {
*jt = boost::transformtowood(*it);
}
for (Forest::const_iterator it = forest.begin(); it != forest.end(); ++it{
std::makeplywood(*it);
}
(Sé que este pastel de código contiene errores sintácticos).
El beneficio es lo más importante al escribir programas informáticos: código más fácil de entender . No estoy al tanto de ninguna consideración de rendimiento.
C ++ permite, hasta cierto punto, hacer la Programación Funcional . Considera esto:
std::for_each( begin, end, doer );
El problema con esto es que la función (objeto) doer
- especifica lo que se hace en el ciclo
- aún oculta algo de lo que realmente se hace (hay que buscar la implementación del
operator()
del objeto de funciónoperator()
) - debe definirse en un ámbito diferente de la llamada
std::for_each
- contiene una cierta cantidad de código repetitivo
- a menudo es un código descartable que no se usa para nada más que esta construcción de un solo ciclo
Lambdas mejora considerablemente en todos estos (y tal vez un poco más lo olvidé).
Aunque creo que otras partes de C ++ 0x son más importantes , las lambdas son más que solo "azúcar sintáctico" para los objetos de función de estilo C ++ 98, porque pueden capturar contextos, y lo hacen por su nombre y luego pueden tomar esos contextos en otros lugares y ejecutar. Esto es algo nuevo, no algo que "compila más rápido / más lento".
#include <iostream>
#include <vector>
#include <functional>
void something_else(std::function<void()> f)
{
f(); // A closure! I wonder if we can write in CPS now...
}
int main()
{
std::vector<int> v(10,0);
std::function<void ()> f = [&](){ std::cout << v.size() << std::endl; };
something_else(f);
}