2010-07-01 21 views
8

In C++ 0x, mi chiedo quale sia il tipo di una funzione lambda. In particolare:Qual è il tipo di una funzione lambda?

#include<iostream> 

type1 foo(int x){ 
return [x](int y)->int{return x * y;}; 
} 

int main(){ 

std::cout<<foo(3)(4);//would output 12 

type2 bar = foo(5); 
std::cout<<bar(6);//would output 30 
return 0; 
} 

Cosa devo sostituire con tipo1/tipo2 per ottenere il funzionamento di sopra? Spero che tu possa vedere quello che sto cercando di realizzare, quindi anche se questo non è possibile tramite una sostituzione diretta di type1 e type2, forse puoi guidarmi nella giusta direzione.

In altre parole:

  • Come posso ottenere una funzione per restituire una funzione anonima?
  • Come posso assegnare una funzione anonima a una variabile?

Grazie!

Edit: Sto compilando con Visual Studio 2010

risposta

14

Non si può mai sapere il tipo di funzione lambda perché ciò che accade logicamente è il compilatore genera una classe (locale) con la funzione l'operatore di chiamata è sovraccarico e una chiusura lessicale è rappresentata dai membri dati di quella classe (locale). Questo è ciò che accade logicamente per una funzione lambda come ad esempio:

auto foo = [](int x, int y) { return x + y; }; 

Il compilatore fa logicamente questo:

struct CompilerGeneratedName { void operator()(int x, int y) const { return x + y; } }; 
CompilerGeneratedName foo; 

Dal momento che il compilatore genera una classe (locale), si genera un nome e quindi si può non scrivere mai esplicitamente il tipo, puoi solo dedurlo dal tipo deduzioni degli argomenti della funzione template o usando auto/decltype.

Anche le chiusure di C++ 0x sono allocate staticamente, quindi non è possibile restituire in modo sicuro una chiusura raw di C++ 0x.

Ancora ci sono alcuni modi per ottenerlo, il primo è più flessibile e supporta le funzioni lambda che catturano gli ambiti lessicali. Usa la funzione std :: se hai una funzione lambda che non cattura nulla dall'ambito esterno allora puoi usare i puntatori di funzione, ma questa conversione è più utile per lavorare con il codice legacy che altro.

Quindi, in pratica ciò che si vuole è questo:

std::function< int (int) > foo(int x) 
{ 
    return [x](int y)->int{return x * y;}; 
} 

Il motivo per cui ho continuato a dire logicamente, è perché questo è come boost :: lambda tipo di opere originariamente (anche se C++ 03 non consente alle classi locali di essere utilizzate negli argomenti della funzione template) e da dove proviene l'idea di aggiungere funzioni lambda, ma poiché questa è una funzione linguistica ora i produttori di compilatori potrebbero implementarla in modi diversi e più efficienti come quando si acquisisce tutto l'ambiente facendo riferimento al compilatore può semplicemente passare un puntatore allo stack di chiamate invece del modo logico mantenendo comunque la vista logica.

+0

Grazie, +1. Cosa intendi con "se la funzione lambda non cattura nulla dall'ambito esterno, allora puoi usare i puntatori di funzione".? Non sta catturando la x? – Cam

+0

@incrediman sì il tuo esempio è in acquisizione quindi non è possibile utilizzare i puntatori di funzione, solo le funzioni lambda che sono stateless possono essere convertite in puntatori di funzioni. –

+0

@snk_kid: Oh. In realtà ho solo interpretato erroneamente ciò che hai scritto, ha perfettamente senso così com'è :) – Cam

6

Da Wikipedia:

le funzioni lambda sono oggetti funzione di un tipo di implementazione-dipendente; il nome di questo tipo è disponibile solo per il compilatore. Se l'utente desidera utilizzare una funzione lambda come parametro, il tipo deve essere un tipo di modello oppure deve creare un valore std::function per acquisire il valore lambda.

VC10 compila questo

//Beware, brain-compiled code ahead! 
#include<iostream> 
#include<functional> 

std::function<int(int)> foo(int x) 
{ 
    return [x](int y)->int{return x * y;}; 
} 

int main(){ 

    std::cout<<foo(3)(4) << '\n'; 

    auto bar = foo(5); 
    std::cout<<bar(6) << '\n'; 

    return 0; 
} 

e stampe

 
12 
30 
+0

Questo funziona perfettamente, grazie! Qualche idea su cosa std :: function fa per renderlo possibile? – Cam

+0

std :: function fa template magic, simile a ciò che std :: bind1st fa, tranne std :: function è molto più facile da usare :-). Si basa sul framework boost :: function, che puoi vedere qui http://www.boost.org/doc/libs/1_43_0/doc/html/function/tutorial.html#id866455. In definitiva, std :: function sta creando una nuova classe (usando i template). Questa nuova classe utilizza il cast implicito per trasformare la funzione lambda nella nuova classe. – Dragontamer5788

Problemi correlati