In generale, a meno che non si usi il cast, è necessario affidarsi a g ++.
Mentre è vero che nessuno dei tipi di funzione che si menzionano può essere esportato per l'uso da C, questo non è ciò che si sta chiedendo. Stai chiedendo quali funzioni puoi passare come puntatore a funzione.
Per rispondere a ciò che puoi passare, penso che sia più costruttivo capire cosa non puoi passare. Non è possibile passare nulla che richiede argomenti aggiuntivi non esplicitamente indicati nell'elenco degli argomenti.
Quindi, nessun metodo non statico. Hanno bisogno di un "questo" implicito. C non saprà passarlo. Quindi di nuovo, il compilatore non ti lascerà.
Nessun lambda di cattura. Richiedono un argomento implicito con l'attuale corpo di lambda.
Ciò che è possibile passare sono i puntatori di funzioni che non richiedono un contesto implicito. A dire il vero, sei andato avanti e li hai elencati:
- Puntatore funzione. Non importa se si tratta di una funzione standard o di un modello, purché il modello sia completamente risolto. Questo non è un problema. Qualsiasi sintassi scritta che risulta in un puntatore a funzione risolverà completamente il modello automaticamente.
- Lambdons non di cattura. Questo è un work-around speciale introdotto da C++ 11 quando introduce lambda. Poiché è possibile farlo, il compilatore esegue la conversione esplicita richiesta per farlo accadere.
- Metodi statici. Dal momento che sono statici, non ricevono un implicito
this
, quindi sono a posto.
L'ultimo si espande. Molti meccanismi di callback C ottengono un puntatore a funzione e un vuoto * opaq. La seguente è una standard ed abbastanza sicuro di poter essere utilizzate con una classe C++:
class Something {
void callback() {
// Body goes here
}
static void exported_callback(void *opaq) {
static_cast<Something*>(opaq)->callback();
}
}
E poi fare:
Something something;
register_callback(Something::exported_callback, &something);
A cura di aggiungere: L'unico motivo per cui funziona è perché il C++ la convenzione di chiamata e la convenzione di chiamata C sono identiche quando non vengono passati argomenti impliciti. C'è una differenza nel manomissione dei nomi, ma non è rilevante quando si passa un puntatore a funzione, poiché l'unico scopo del manomissione dei nomi è di consentire al linker di trovare l'indirizzo della funzione corretta.
Se avessi provato quel trucco con una callback che si aspettava, ad esempio, una convenzione di chiamata stdcall o pascal, questo schema sarebbe caduto in superficie.
Questo, tuttavia, non è univoco per i metodi statici, lambda e le funzioni del modello. Anche una funzione standard fallirebbe in tali circostanze.
#define stdcall __attribute__((stdcall))
typedef stdcall void (*callback_type)(void *);
risultati in::
test.cpp:2:45: warning: ‘stdcall’ attribute ignored [-Wattributes]
typedef stdcall void (*callback_type)(void *);
_ "ma metto in dubbio la sicurezza quando vengono utilizzate diverse convenzioni di chiamata e binding di linguaggio per le funzioni C e C++" _ Non ci sono differenze come queste quando tutto è stato compilato in modo coerente per l'ambiente di destinazione. –
Le funzioni membro statiche, le funzioni modello specializzate e i lambda non catturanti non possono ricevere una convenzione di chiamata "C" esterna così formalmente che non è buona. Ma in pratica dipende dal compilatore.E come problema di in-practice, il problema principale non è che non funzionerà, ma che alcuni compilatori possono produrre stupidi avvertimenti sul formale. –
@ Cheersandhth.-Alf, quello non dovrebbe importare. La libreria C dovrebbe essere in grado di chiamare una funzione il cui nome viene manomesso dal compilatore C++ senza problemi. –