2014-05-06 11 views
7

So che le liste di acquisizione rendono variabili disponibili all'interno di un corpo funzione lambda in questo modo:In che modo gli elenchi di cattura di lambda funzionano effettivamente in C++ 11?

int pos(0); 
std::function<void()> incPos = [&pos](){ ++pos; }; 
incPos(); //pos is now 1 

Ma come si fa che la cattura effettivamente lavorare a livello compilatore? Dove sono archiviati gli indirizzi catturati oi valori catturati?

+1

Lambdas sono essenzialmente [functors] (http://en.wikipedia.org/wiki/Function_object) che non è necessario scrivere da soli. –

risposta

9

Ogni espressione lambda genera un oggetto funzione univoco (chiusura) che memorizza le variabili acquisite come membri dati. Per esempio, l'espressione lambda nel codice sarebbe trasformata in qualcosa di simile dal compilatore:

struct __uniquely_named_lambda 
{ 
    __uniquely_named_lambda(int& pos) 
    : pos(pos) {} 
    int& pos; 

    void operator()() const 
    { ++pos; } 
}; 

Invocando la lambda è semplicemente una chiamata a operator().

Il membro dati è un riferimento poiché è stato acquisito per riferimento. Se catturato dal valore sarebbe un semplice int. Si noti inoltre che generato operator() è const per impostazione predefinita. Questo è il motivo per cui non è possibile modificare le variabili catturate a meno che non si utilizzi la parola chiave mutable.

+0

Nota, tuttavia, che quanto sopra non è ** esattamente ciò che accade. A differenza del magico 'for' loop e della maggior parte del resto del C++, è il comportamento che è standardizzato e che il comportamento non è codificato nel codice C++. In particolare, la suddetta "falsa" lambda ha un costruttore - gli stessi lambda non ne hanno bisogno (possono farlo tramite la magia). Inoltre, se si passa il suddetto "fake" lambda come riferimento, esso rimane valido fino a quando i dati di riferimento sono validi - un lambda reale richiede tecnicamente sia i dati ** che ** la variabile di riferimento che ha catturato rimane valida. – Yakk

+1

@Yakk: In base alla regola as-if, i compilatori hanno sempre avuto la libertà di implementare C++ in qualsiasi modo la ricerca appropriata fintanto che il comportamento osservabile è identico. L'esistenza di costruttori non è osservabile. – MSalters

+0

@msalters Usa la deduzione del tipo e quindi le classi dei tratti. Alcuni di essi differiscono in base all'esistenza del costruttore. È possibile rilevare i cori unari non espliciti (anche se privati) tramite sovraccarichi di funzione (di nuovo, tipo tramite deduzione di tipo), ma non certo se io possa fare lo stesso con esplicito o multi-arg (la costruzione di thinkimg '{}' con sovraccarichi?) - Non sono convinto che non sia osservabile, ma non certo. – Yakk

Problemi correlati