Lambda Aufruf Konvention
-
typedef void (__stdcall *Func)(int); void test(Func){} void __stdcall valid(int){} int main(){ test(valid); test([](int){}); }E:\...\test.cpp|7|error: cannot convert 'main()::<lambda(int)>' to 'Func {aka void (__attribute__((__stdcall__)) *)(int)}' for argument '1' to 'void test(Func)'|Verwenden tue ich den mit Code::Blocks 12.11 mitgelieferten MinGW32 Compiler mit gcc version 4.7.1 (tdm-1).
-
Aus einem mir unverständlichen Grund hat man entschieden, dass man den Typ eines Lambdas nicht hinschreiben können darf. Du versuchst in deiner Testfunktion den Typ eines Lambdas anzugeben und genau das soll nicht möglich sein (warum auch immer). Entweder du benutzt std::function und nimmst dynamische Speicherallokation in Kauf oder du machst ein Template draus. Dafür zu sorgen, dass ein Lambda kompatibel zu einem void (__stdcall *)(int) ist soll nicht möglich sein.
-
hmm, komisch ... hätte gedacht, dass der Compiler selbst so schlau wäre und sich anhand der impliziten Konvertierung von Lambda zu Funkionszeiger selbst die richtige Aufrufkonvention verwenden kann. Zumindest wurde in den Lambda-Proposals so etwas erwähnt. Man wolle auch C-APIs mit Lambdas bedienen können.
Also entweder verlangt der Standard von einem Compiler so eine Automatik, wobei der GCC 4.7 das dann offensichtlich noch nicht kann, oder Du erwartest zu viel an Magie.
Schau mal, ob du hier fündig wirst:
http://open-std.org/JTC1/SC22/WG21/
-
nwp3 schrieb:
...
Ein Lambda-Ausdruck mit leerer Capture-Clause ist implizit zu einem Funktionszeiger konvertierbar. Genau das wollte der OP hier machen. Ihm steht nur das
__stdcallim Weg. Von__stdcallsteht natürlich nichts im Standard, auch wenn dastddrin vorkommt. Von daher kann man in diesem Fall auch nicht wirklich darüber sprechen, ob der Compiler sich hier konform verhält oder ob das wirklich nicht erlaubt ist. Es sieht für mich nach einer QoI (quality of implementation) Sache aus. Der GCC könnte dieses Auto-Magie-Feature unabhängig vom Standard einbauen. Ich weiß nur nicht, wie da die Chancen stehen. stdcall gibt's ja AFAIK auch nur in der Windows-Welt.
-
krümelkacker schrieb:
nwp3 schrieb:
...
Ein Lambda-Ausdruck mit leerer Capture-Clause ist implizit zu einem Funktionszeiger konvertierbar. Genau das wollte der OP hier machen. Ihm steht nur das
__stdcallim Weg. Von__stdcallsteht natürlich nichts im Standard, auch wenn dastddrin vorkommt. Von daher kann man in diesem Fall auch nicht wirklich darüber sprechen, ob der Compiler sich hier konform verhält oder ob das wirklich nicht erlaubt ist. Es sieht für mich nach einer QoI (quality of implementation) Sache aus. Der GCC könnte dieses Auto-Magie-Feature unabhängig vom Standard einbauen. Ich weiß nur nicht, wie da die Chancen stehen. stdcall gibt's ja AFAIK auch nur in der Windows-Welt.Solche Magie würde ggf. zu Codeduplikation führen (die Konvertierung in eine Funktionszeiger muss ja nicht immer im Kontext des Lamdaausdrucks erfolgen).
Auf die Schnelle finde ich Proposal für lamda-Fpointer-Konvertierung (angenommen) und
Defekt #1557 wobei die vorgeschlagene Lösung eher nicht darauf abziehlt, polymorphe Aufrufkonventionen zu erlauben (wobei Linkage ja nur indirekt etwas mit der Aufrufkonvention (=ABI-Feature) zu tun hat).
-
Youka schrieb:
Ich muss z.B. eine Funktion mit __stdcall übergeben, Lambdas werden allerdings immer mit __cdecl erstellt.
Ugh, gibt es unter Windows immer noch keine einheitliche Calling Convention? Dachte dieses DOS-Relikt hätte man längst beseitigt.
-
Calling Conventions sind kein DOS-Relikt. (Die Behauptung macht nichtmal Sinn. Man könnte behaupten, dass Windows mit stdcall arbeitet ist ein "DOS-Relikt" (ist es nicht, weil in der DOS-API völlig andere Calling Conventions üblich waren. Das ist also höchstens ein Windows-Relikt...))
-
Das gibt's auch auf allen anderen Plattformen. Nur machen unter *NIX alle cdecl, so dass man da in C-Code nichts von merkt. Wenn du unter Linux Pascal-Code schreibst (ich weiß, macht niemand mehr, und das ist auch besser so), musst du Funktionen aus C-Bibliotheken mit cdecl kennzeichnen, denn da hat man per default üblicherweise stdcall.
Das wird man auch nicht mehr los, weil Kompatibilität.
-
Die AMD64 ABI von *NIX ist kein cdecl mehr und unterscheidet sich auch bei Systemaufrufen.
-
Danke für eure Antworten.
Dies bestätigt leider meine weiteren Funde im Web, schade
Hoffe ich mal, das wird in späteren Compilern unterstützt.