Tratando de entender lambdas en C++, lo que no entiendo es esto:
int multiplier = 5;
auto timesFive = [multiplier](int a) { return a * multiplier; };
std::cout << timesFive(2) << '\n'; // Prints 10
multiplier = 15;
std::cout << timesFive(2) << '\n'; // Still prints 2*5 == 10 (???) - Should it be 30?
Cuando el programa llama al timesFive()
la segunda vez, espero que el resultado sea 30. Pero, ¿por qué el resultado es Still prints 2*5 == 10
no prints 2*15 == 30
? Quizás la función lambda de alguna manera no puede rastrear el valor de multiplier
a pesar de que ya hemos intentado capturarlo?
¿Y cuál es la manera de obtener el resultado deseado?
Rudi
capturaste multiplier
por valor, lo que significa que se copió en la lambda. Necesitas capturarlo por referencia:
int multiplier = 5;
auto timesFive = [&multiplier](int a) { return a * multiplier; };
std::cout << timesFive(2);
multiplier = 15;
std::cout << timesFive(2);
-
Además, si realmente desea este comportamiento, el nombre
timesFive
es más que un poco engañoso–Steve Cox
29 de agosto de 2016 a las 14:03
-
@SteveCox Estoy bastante seguro de que este es solo un ejemplo académico que muestra un concepto. También podríamos llamarlo foo, foobar, …. Por supuesto que tienes razón, si ese fuera un ejemplo del mundo real.
– exiliar
2 de septiembre de 2016 a las 7:02
Lambdas son azúcar sintáctico para una clase innombrable y la instancia de la misma. A veces, expandir su código a lo que esta clase innombrable puede ayudar a comprender lo que está sucediendo.
[ capture_list ]( arg_list ) -> return_value_clause_opt { body };
se vuelve muy aproximadamente (pseudo-código):
struct anonymous_type {
capture_list;
auto operator()( arg_list ) const -> return_value_clause_opt {
body
}
anonymous_type( capture_list_in ):capture_list(capture_list_in) {}
};
Si lista una variable en capture_list
por su simple nombre, es copiado en una copia dentro de la clase anónima.
Entonces tus timesFive
convertirse
struct __secret_name__ {
int multiplier;
int operator()(int a) const { return a*multiplier; }
};
int multiplier = 5;
auto timesFive = __secret_name__{multiplier};
Debería quedar bastante claro que cambiar multiplier
en el código anterior no cambiará el comportamiento de timesFive
.
si pones un &
delante del nombre, un no-const
referencia se coloca dentro de la clase anónima.
struct __secret_name__ {
int& multiplier;
int operator()(int a) const { return a*multiplier; }
};
int multiplier = 5;
auto timesFive = __secret_name__{multiplier};
ahora, cambiando multiplier
va a cambiar el comportamiento de timesFive
porque timesFive
sostiene un referencia al multiplicador, no una copia del mismo.
Algunos detalles saltados arriba por brevedad. El nombre __secret_name__
es solo para exposición. Las variables miembro de la lamba no son realmente públicas. La lambda, que es trivialmente construible, está definida por la implementación, incluso si sus datos lo están. Etc.
-
Buena idea. Hace mucho tiempo, teníamos Cfront, cortesía de Bjarne Stroustrup, para obtener el “funcionamiento interno” de C++. ¿Hay algo similar en estos días? ¿Cómo conjeturaste tu pseudocódigo? ¿intuición?
– lápiz negro
30 de agosto de 2016 a las 0:31
-
@black el estándar describe qué es una lambda. No es tan “como si” como
for(:)
bucles, pero es muy explícito.– Yakk – Adam Nevraumont
7 sep 2016 a las 12:34
Por favor, haga que el título describa el problema. Sí, está tratando de entender las lambdas, pero eso no nos dice mucho sobre lo que realmente está preguntando. (Estaba considerando editarlo yo mismo, pero no me gustaron las ideas que se me ocurrieron).
– jpmc26
29 ago 2016 a las 21:02