2012-07-22 12 views
24

Il codice seguente stampa 0, ma mi aspetto di vedere un 1. La mia conclusione è che le funzioni lambda non vengono invocate passando effettivamente i parametri catturati alle funzioni, che è più intuitivo. Ho ragione o mi manca qualcosa?C++ 11 cattura lambda per valore catturato al punto di dichiarazione

#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; 
} 

risposta

23

le funzioni lambda sono invocate effettivamente passando i parametri acquisiti alla funzione.

value è uguale a 0 nel punto in cui è definita la lambda (e viene acquisito value). Poiché stai acquisendo per valore, non importa cosa fai a value dopo l'acquisizione.

Se avessi catturato value come riferimento, vedresti un 1 stampato perché anche se il punto di cattura è sempre lo stesso (la definizione lambda) si stampa il valore corrente dell'oggetto catturato e non una copia ne ha creato quando è stato catturato.

+0

grazie. Stavo pensando al valore di-come in quanto gli aggiornamenti di valore non saranno visibili al di fuori della funzione. Tuttavia, sembra che questo significhi anche che gli aggiornamenti al di fuori della funzione non saranno visibili all'interno della funzione. – perreal

+6

Quello che potrebbe essere fuorviante qui è la dicitura: per valore significa "genera una copia". Il lambda ha una copia della variabile, il suo valore è preso al punto di dichiarazione della lambda. Poiché il lambda ha una copia privata, l'oggetto originale non viene modificato o letto all'interno del lambda. Ecco perché in realtà esiste un'acquisizione per riferimento, per consentire il caso in cui si desidera vedere/modificare l'originale. – Klaim

12

Sì, le catture vengono eseguite nel momento in cui viene dichiarata la lambda, non quando viene chiamata. Pensa a un lambda come oggetto funzione il cui costruttore prende le variabili catturate come parametri e le assegna alle relative variabili membro (valori o riferimenti, a seconda della modalità di cattura). L'attuale chiamata del lambda non ha magia, è solo un normale chiamata operator() dell'oggetto funzionale sottostante.

Catturare le cose al punto di chiamata non avrebbe molto senso: cosa sarebbe catturato se il lambda fosse restituito o passato come parametro a un'altra funzione e chiamato lì? Esistono in realtà linguaggi che si comportano in questo modo: se si fa riferimento a una variabile x in una funzione, si presume che faccia riferimento a qualsiasi variabile denominata x attualmente in ambito al punto di chiamata. Questo è chiamato ambito dinamico. L'alternativa, usata dalla maggior parte dei linguaggi perché rende molto più semplice ragionare sui programmi, è chiamata scoping lessicale.

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

5

Il problema è che la funzione di stampa è catturare per valore e non per riferimento.

#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; 
} 

Uscite 0 e 1 come previsto. Il primo viene catturato dal valore e stampa il valore nel punto di cattura; il secondo acquisisce il riferimento e quindi ne stampa il valore.

Problemi correlati