2010-05-29 14 views
15

Ieri stavo pensando se sarebbe stato possibile utilizzare la comodità delle funzioni lambda C++ 0x per scrivere callback per le funzioni dell'API di Windows.Il C++ 0x supporterà __stdcall o extern "C" capture-nothing lambdas?

Ad esempio, cosa succede se volevo utilizzare una lambda come EnumChildProc con EnumChildWindows? Qualcosa di simile:

EnumChildWindows(hTrayWnd, CALLBACK [](HWND hWnd, LPARAM lParam) { 
     // ... 
     return static_cast<BOOL>(TRUE); // continue enumerating 
    }, reinterpret_cast<LPARAM>(&myData)); 

Un altro utilizzo potrebbe essere quello di scrivere extern "C" callback per routine C. Es .:

my_class *pRes = static_cast<my_class*>(bsearch(&key, myClassObjectsArr, myClassObjectsArr_size, sizeof(my_class), extern "C" [](const void *pV1, const void *pV2) { 
     const my_class& o1 = *static_cast<const my_class*>(pV1); 
     const my_class& o2 = *static_cast<const my_class*>(pV2); 

     int res; 
     // ... 
     return res; 
    })); 

È possibile?

Posso capire che lambda che cattura le variabili non sarà mai compatibile con C, ma almeno mi sembra possibile che capture-nothing lambda sia compatibile.

+0

Questo è stato chiarito in un rapporto sui difetti rispetto allo standard C++ 11, come spiegherò nella mia risposta di seguito. –

risposta

14

Lambdas senza acquisizione are implicitly convertible a un puntatore alla funzione (mediante una funzione di conversione non esplicita definita dal tipo di chiusura).

L'FCD non sembra specificare quale collegamento di linguaggio ha il tipo di funzione di quel tipo di puntatore a funzione, quindi se è necessario passare questo puntatore a funzioni C, la convenzione di chiamata delle funzioni C++ e le funzioni C devono essere stesso. Credo che su Windows, questo è il caso però. Così si dovrebbe essere in grado di passare il lambda di funzioni API di Windows

typedef void(*callbackType)(void *userData); 
extern "C" void someCFunction(callbackType callback); 

int main() { 
    someCFunction([](void *userData) { /* ... */ }); 
} 

FCD formulazione a 5.1.2/6:

Il tipo di chiusura per una lambda espressione senza lambda-acquisizione ha un pubblico non virtuale funzione di conversione const non esplicita per puntare alla funzione con lo stesso parametro e tipi di ritorno dell'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, invocata, ha lo stesso effetto di richiamo dell'operatore di chiamata di funzione del tipo di chiusura.

penso che il finale standard dovrebbe avere una nota che dice che c'è una funzione di conversione per entrambi i C puntatori a funzione di collegamento e C++ puntatori a funzione di collegamento, come la convertibilità di puntatori a funzione C è uno degli obiettivi di questa funzionalità.

2

Non c'è una ragione particolarmente buona per cui questo non debba essere esteso alla cattura di lambda. Richiede una certa generazione di codice dinamico, ma non dovrebbe essere al di là dell'umorismo degli scrittori di compilatori, e renderebbe più semplice l'interoperabilità con le vecchie API C di ordini di grandezza - non è più necessario passare i parametri attraverso void * s non tipizzato (che non tutti Le API offrono anche).

+1

Il problema non è la generazione di codice dinamico, è la pulizia del codice dinamico. Dovresti avere un GC a livello di lingua per ripulire quel codice. – Puppy

+2

Non più di qualsiasi altra cosa in C++. Un shared_ptr a un thunk sarebbe sufficiente. – DrPizza

1

Il collegamento linguaggio dei risultati puntatore a funzione da una conversione di un lambda cattura-meno non è stato specificato nello standard C++ 11, ma è stato affrontato in defect report 1557 che dice:

5.1.2 [expr .prim.lambda] il paragrafo 6 non specifica il collegamento linguistico del tipo di funzione della funzione di conversione del tipo di chiusura.

e la risoluzione era che il legame linguaggio dovrebbe essere C++:

Il tipo di chiusura per una lambda espressione senza lambda-capture ha una funzione pubblica non virtuale non esplicita di conversione const a puntatore a funzionare con il linguaggio C++ (7.5 [dcl.link]). avere lo stesso parametro e tipi di ritorno dell'operatore di chiamata di funzione del tipo di chiusura. Il valore restituito ...

possiamo trovare questo linguaggio nel progetto di C++ 14 di serie, dal momento che lo stato è DRWP sembra che questo non vale per C++ 11.

+0

Grande scoperta. Ma se fosse un difetto sollevato e accettato durante la vita di C++ 11, sicuramente questo significa che sicuramente ** fa ** si applica a C++ 11? –

+0

@underscore_d se guardiamo alla [lista dei problemi attivi correnti] (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html) che definisce i termini come "DRWP" è detto : 'Un problema di DR la cui risoluzione si riflette nel documento di lavoro corrente. Il Working Paper è una bozza per una versione futura dello standard. Che per quanto posso dire significa che si applica a C++ 14 non C++ 11. –