2014-11-09 8 views
16

Poiché so che tutti i tipi di dati devono essere noti al momento della compilazione e lambda non è un tipo. Lambda è stato tradotto in anonymous struct with operator() o std::function incartato?In che tipo vengono compilati i lambda?

Ad esempio,

std::for_each(v.begin(), v.end(), [](int n&){n++;}); 
+2

'std :: function' non ha connessioni di lingua come' std :: initializer_list'. – chris

+0

Deriva dalla mia mancanza di conoscenza. Puramente casuale. – texasbruce

+2

Il tipo di Lambda è [non specificato] (http://stackoverflow.com/questions/7951377/che-è-il-tipo-di-lambda-qualificato-con-auto-in-c11). – Marcin

risposta

14

Una variante del as-if rule, lo standard C++ 11 dice :

§5.1.2/3 [..] L'esecuzione può definire il tipo di chiusura diversamente da quanto descritto qui di seguito fornita ciò non altera il comportamento osservabile del programma diverso modificando:

- la dimensione e/o allineamento del tipo di chiusura,

- se il tipo di chiusura è banalmente copiabile (clausola 9),

- se il tipo di chiusura è una classe standard di layout (clausola 9), o

- se il tipo di chiusura è una classe POD (Clausola 9).

Credo che questo sia ciò che le persone intendono quando dicono che è unspecified. Tuttavia ciò che è garantito come già detto nelle altre risposte è la seguente:

autore originale: Lightness Races in Orbit

[C++11: 5.1.2/3]:Il tipo di lambda-espressione (che è anche il tipo di chiusura oggetto) è un unico, senza nome non sindacale tipo di classe - chiamato il tipo chiusura - le cui proprietà sono d indicato di seguito. Questo tipo di classe non è un aggregato (8.5.1). Il tipo di chiusura viene dichiarato nell'ambito di ambito più piccolo, nell'ambito della classe o nell'ambito dello spazio dei nomi che contiene la corrispondente espressione lambda. [..]

La clausola prosegue elencando diverse proprietà di questo tipo. Qui alcuni punti salienti:

[C++11: 5.1.2/5]: Il tipo di chiusura per un lambda-espressione ha un pubblico inline operatore chiamata di funzione (13.5.4) i cui parametri e tipo di ritorno sono descritti dalla lambda-espressione parametro-dichiarazione-clausola e trailing-return-type rispettivamente. [..]

[C++11: 5.1.2/6]: Il tipo di chiusura per una lambda-espressione senza lambda-capture ha un non-esplicito const pubblica funzione non virtuale conversione a puntatore a funzione con lo stesso parametro e restituire i tipi come operatore di chiamata di funzione del tipo di chiusura. Il valore restituito da questa funzione di conversione deve essere l'indirizzo di una funzione che, se richiamata, ha lo stesso effetto del richiamo dell'operatore di chiamata di tipo del tipo di chiusura .

6

Un'espressione lambda costruisce un tipo senza nome, con ciascuno avente un tipo diverso. Non sono implementazioni std::function. Per saperne di più è fornito qui: What is a lambda expression in C++11? e qui: How to convert a lambda to an std::function using templates

Puoi svelare il tipo sul vostro compilatore specifico con un trucco del genere:

void foo(int); 

int main() { 
    auto a = []{ return 1; }; 
    auto b = []{ return 1; }; 

    foo(a); 

    foo(b); 

    return 0; 
} 

compilazione con clangore sul mio mac dà:

/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:11:5: error: no matching function for call to 'foo' 
    foo(a); 
    ^~~ 
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:5:6: note: candidate function not viable: no known conversion from 
'<lambda at /Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:8:14>' to 'int' for 1st argument 
void foo(int); 
    ^
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:13:5: error: no matching function for call to 'foo' 
    foo(b); 
    ^~~ 
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:5:6: note: candidate function not viable: no known conversion from 
'<lambda at /Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:9:14>' to 'int' for 1st argument 
void foo(int); 

@Barry indica che è possibile utilizzare typeid invece. Se stampo fuori typeid(a).name() e typeid(b).name() sul mio sistema, ottengo:

Z4mainE3$_0 
Z4mainE3$_1 

che demangle a

main::$_0 
main::$_1 

Volevo solo includere questo per completezza. In realtà trovo la versione del messaggio di errore un po 'più informativa. :)

+0

Quindi è una struttura anonima? – texasbruce

+0

Come per le elaborazioni di @ texasbruce, hanno un tipo, ma è un dettaglio di implementazione. – sfjac

+1

@sfjac Se vuoi veramente guardare il tipo, puoi semplicemente usare 'typeid()' e passarlo attraverso un [demangler] (http://stackoverflow.com/questions/281818/unmangling-the-result-of -stdtype-infoname) – Barry

12

Dal §5.1.2.3 di serie:

Il tipo di lambda-espressione ... è un unico, senza nome non sindacale tipo di classe

E ' il suo tipo Ogni volta. Così, per esempio:

auto a = []{ return 1; }; 
auto b = []{ return 1; }; 

a e b avrà necessariamente tipi diversi. Sono entrambi convertibili in std::function<int()>, ma non gli uni agli altri:

std::function<int()> c = a; // OK 
a = b; // NOPE 

Aggiunta di un paio di esempi per aggiungere un po 'di chiarezza:

decltype(a) a2 = a; // OK, explicitly specifying the correct type 

template <typename F> 
void foo(F f) { ... } 

foo(a); // calls foo<decltype(a)>, not foo<std::function<int()> 
+0

Questo non risponde alla mia domanda. So che lambda non ha un tipo (come ho affermato nella domanda). La mia domanda è come sono compilati poiché non hanno tipo. – texasbruce

+5

@texasbruce Hai frainteso. Loro * fanno * hanno un tipo. È solo * unico * e * senza nome *. Nel mio esempio, puoi usare 'using T = decltype (a); T a2 = a; 'Questo verrà compilato bene. – Barry

+0

@texasbruce: la risposta dice che il tipo di espressione lambda è un tipo di classe non unione univoco, senza nome. Questa è una dichiarazione diversa da "non ha un tipo". Un lambda * ha * un tipo, ma il tipo non ha un nome. – rici

Problemi correlati