2013-04-13 10 views
8

Si consideri il seguente codice:Passando lambda dichiarato utilizzando auto-parola chiave con riferimento non-const come argomento a std :: tipo di parametro funzione

#include <iostream> 
#include <functional> 

// passing function object by value 
void foo(std::function<int(int, int)> f) { 
    std::cout << f(3, 7) << std::endl; 
} 

// passing const function object by reference 
void bar(const std::function<int(int, int)> & f) { 
    std::cout << f(3, 7) << std::endl; 
} 

// passing non-const function object by reference 
void fizz(std::function<int(int, int)> & f) { 
    std::cout << f(3, 7) << std::endl; 
} 

int main() { 

    std::function<int(int, int)> g1 = [] (int x, int y) { return x * y; }; 
    auto g2 = [] (int x, int y) { return x * y; }; 

    foo(g1); // OK 
    foo(g2); // OK 
    bar(g1); // OK 
    bar(g2); // OK 
    fizz(g1); // OK 

    // compile error: 
    // error: invalid initialization of reference of type 
    // 'std::function<int(int, int)>&' from expression of type 
    // 'main()::<lambda(int, int)>' 
    // error: in passing argument 1 of 'void fizz(std::function<int(int, int)>&)' 
    fizz(g2); 

} 

qualcuno dovrebbe spiegare a me:

(a) Perché fizz(g2) genera un errore di compilazione e gli altri costrutti no? Sembra che possa passare un lambda per riferimento se inserisco esplicitamente il suo tipo nella sua dichiarazione, ma non se uso la parola chiave auto, OPPURE se dichiaro il tipo di parametro funzione come const.

(b) Cosa faconst nel tipo di parametro funzione significa qui?

(c) In quali circostanze avrei preferisco passare per valore piuttosto che fare riferimento (UPDATE: ora una domanda separata: C++11: pass (lambda or other) function object by reference or value?)?

Grazie per qualsiasi intuizione.

risposta

9

Nella custodia fizz(g1), g1 è già un std::function. Pertanto, non c'è bisogno di una conversione implicita. Quindi il parametro fizz è un riferimento non costante a g1.

In fizz(g2), g2 non è un std::function. Pertanto, il compilatore deve eseguire una conversione implicita. E la conversione implicita restituisce un temporaneo.

Gli oggetti temporanei non possono essere associati a riferimenti non const; possono collegarsi solo ai riferimenti o ai valori const. Da qui l'errore del compilatore.

Cosa significa const nel tipo di parametro funzione qui?

È possibile chiamare solo const membri dell'oggetto, non è possibile convertire implicitamente a non const, e non è possibile eseguire operazioni non const sui suoi membri.

Sai, proprio come qualsiasi altro uso di const.

In genere, quando una funzione accetta un parametro tramite riferimento non const, sta dicendo qualcosa di molto speciale su cosa intende fare con quel parametro. Vale a dire, che lo stai consegnando ad un oggetto, e lo farai con cose non costanti (es: modificando quell'oggetto). Ecco perché i temporaries non si legano a riferimenti non const; è probabile che sia un errore dell'utente, poiché il temporaneo potrebbe non aggiornare l'oggetto originale che hai passato.

A meno che l'fizz non modifichi l'oggetto, è necessario passarlo per valore o per const&.

+0

Grazie. Non pensavo che un lambda non fosse di tipo std :: function, quindi si stava verificando una conversione implicita a una funzione std :: temporanea. Inoltre, per qualche ragione, credo che non pensavo che un oggetto std :: function potesse essere modificato, e quindi il const era superfluo. – Jeet

Problemi correlati