Im Allgemeinen sollten Sie, wenn Sie nicht Cast verwenden, g ++ vertrauen.
Es stimmt zwar, dass keiner der von Ihnen genannten Funktionstypen exportiert werden kann, um sie in C zu verwenden. Dies ist jedoch nicht das, was Sie fragen. Sie fragen, welche Funktionen Sie als Funktionszeiger übergeben können.
Um zu beantworten, was Sie passieren können, denke ich, es ist konstruktiver zu verstehen, was Sie nicht passieren können. Sie können nichts übergeben, das zusätzliche Argumente benötigt, die nicht explizit in der Liste der Argumente aufgeführt sind.
Also keine nicht statischen Methoden. Sie brauchen ein implizites "Dies". C wird es nicht weitergeben. Dann wird der Compiler Sie nicht zulassen.
Kein Capturing Lambdas. Sie erfordern ein implizites Argument mit dem tatsächlichen Lambda-Körper.
Was Sie übergeben können, sind Funktionszeiger, die keinen impliziten Kontext erfordern. Als ein Punkt der Tat gingen Sie voran und listeten sie auf:
- Funktionszeiger. Es spielt keine Rolle, ob es sich um eine Standardfunktion oder eine Vorlage handelt, solange die Vorlage vollständig aufgelöst ist. Das ist kein Problem. Jede geschriebene Syntax, die zu einem Funktionszeiger führt, löst die Vorlage automatisch vollständig auf.
- Nicht einfangende Lambdas. Dies ist ein spezieller Work-Around, der von C++ 11 eingeführt wurde, als Lambdas eingeführt wurden. Da dies möglich ist, führt der Compiler die explizite Konvertierung durch, die erforderlich ist, um dies zu ermöglichen.
- Statische Methoden. Da sie statisch sind, werden sie nicht implizit
this
übergeben, also sind sie in Ordnung.
Der letzte trägt sich erweitert. Viele C-Callback-Mechanismen erhalten einen Funktionszeiger und ein void * opaq. Das Folgende ist ein Standard und ziemlich sicher zu ihrer Verwendung mit einer C++ Klasse:
class Something {
void callback() {
// Body goes here
}
static void exported_callback(void *opaq) {
static_cast<Something*>(opaq)->callback();
}
}
Und dann tun:
Something something;
register_callback(Something::exported_callback, &something);
Edited hinzufügen: Der einzige Grund, warum dies funktioniert, ist, weil die C++ Die Aufrufkonvention und die C-Aufrufkonvention sind identisch, wenn keine impliziten Argumente übergeben werden. Es gibt einen Unterschied in der Namensänderung, aber es ist nicht relevant, wenn Sie einen Funktionszeiger übergeben, da der einzige Zweck von Namensfehlern darin besteht, dem Linker zu ermöglichen, die korrekte Funktionsadresse zu finden.
Hätten Sie diesen Trick mit einem Callback versucht, der z. B. eine stdcall- oder Pascal-Aufrufkonvention erwartet, würde dieses Schema flach auf sein Gesicht fallen.
Dies ist jedoch nicht nur für statische Methoden, Lambdas und Vorlagenfunktionen. Selbst eine Standardfunktion würde unter diesen Umständen versagen.
Leider, wenn Sie einen Funktionszeiger auf einen stdcall Typen definieren, gcc ignoriert Sie:
#define stdcall __attribute__((stdcall))
typedef stdcall void (*callback_type)(void *);
Ergebnisse in:
test.cpp:2:45: warning: ‘stdcall’ attribute ignored [-Wattributes]
typedef stdcall void (*callback_type)(void *);
_ "aber ich frage die Sicherheit, wenn verschiedene Aufrufkonventionen und Sprachbindungen für C- und C++ - Funktionen verwendet werden" _ Es gibt keine Unterschiede wie diese, wenn alles konsistent für die Zielumgebung kompiliert wurde. –
Statische Member-Funktionen, spezialisierte Template-Funktionen und nicht erfassende Lambdas können nicht extern "C" Aufruf Konvention so formal, das ist nicht gut. Aber in der Praxis kommt es auf den Compiler an.Und in der Praxis ist das Hauptproblem nicht, dass es nicht funktioniert, sondern dass einige Compiler alberne Warnungen über das Formale produzieren können. –
@ Cheersandthth.-Alf, das sollte nicht wichtig sein. Die C-Bibliothek sollte in der Lage sein, eine Funktion aufzurufen, deren Name durch den C++ - Compiler ohne Probleme verändert wird. –