2012-07-22 10 views
24

El código siguiente imprime 0, pero espero ver un 1. Mi conclusión es que las funciones lambda no se invocan al pasar efectivamente los parámetros capturados a las funciones, que es más intuitivo. ¿Estoy en lo cierto o me estoy perdiendo algo?C++ 11 Captura lambda por capturas de valor en el punto de declaración

#include <iostream> 
int main(int argc, char **argv){ 
    int value = 0; 
    auto incr_value = [&value]() { value++; }; 
    auto print_value = [ value]() { std::cout << value << std::endl; }; 
    incr_value(); 
    print_value(); 
    return 0; 
} 

Respuesta

23

funciones lambda se invocados por realidad pasar parámetros capturados a la función.

value es igual a 0 en el punto donde se define el lambda (y se captura value). Como está capturando por valor, no importa lo que haga a value después de la captura.

Si capturó value por referencia, verá un 1 impreso porque aunque el punto de captura sigue siendo el mismo (la definición lambda) estaría imprimiendo el valor actual del objeto capturado y no una copia creado cuando fue capturado

+0

gracias. Estaba pensando en valor-por, ya que las actualizaciones de valor no serán visibles fuera de la función. Sin embargo, parece que también significa que las actualizaciones fuera de la función no serán visibles dentro de la función. – perreal

+6

Lo que podría ser engañoso aquí es la fraseología: por valor significa "generar una copia". La lambda tiene una copia de la variable, su valor se toma en el punto de declaración de la lambda. Como la lambda tiene una copia privada, el objeto original no se modifica ni se lee dentro de la lambda. Es por eso que hay una captura por referencia en realidad, para permitir que el caso que desea ver/modificar el original. – Klaim

12

Sí, las capturas se realizan en el punto en que se declara el lambda, no cuando se llama. Piense en una lambda como un objeto de función cuyo constructor toma las variables capturadas como parámetros y las asigna a sus correspondientes variables miembro (ya sean valores o referencias, dependiendo del modo de captura). La llamada real de la lambda no tiene magia, es solo una llamada normal operator() del objeto de función subyacente.

Capturar elementos en el punto de llamada no tendría mucho sentido. ¿Qué se capturaría si la lambda se devolviera o pasara como parámetro a otra función y se llamara allí? En realidad, hay idiomas que se comportan de esta manera: si se refiere a una variable x en una función, se supone que se refiere a cualquier variable llamada x actualmente en alcance en el punto de llamada. Esto se llama alcance dinámico. La alternativa, utilizada por la mayoría de los idiomas porque hace que el razonamiento sobre los programas sea mucho más simple, se denomina ámbito léxico.

http://en.wikipedia.org/wiki/Lexical_scoping#Lexical_scoping_and_dynamic_scoping

5

El problema es que su función de impresión está capturando por su valor y no por referencia.

#include <iostream> 
int main(int argc, char **argv){ 
    int value = 0; 
    auto incr_value = [&value]() { value++; }; 
    auto print_value = [ value]() { std::cout << value << std::endl; }; 
    auto print_valueref = [ &value]() { std::cout << value << std::endl; }; 

    incr_value(); 
    print_value(); 
    print_valueref(); 
    return 0; 
} 

Salidas 0 y 1 como se esperaba. El primero se captura por valor e imprime el valor en el punto de captura; el segundo captura la referencia y luego imprime su valor.

Cuestiones relacionadas