Ich bin auf eine Situation gestoßen, die mein neu entstehendes Verständnis von C ++ - Lambdas herausfordert, und ich habe es auf folgende Weise heruntergebrochen:
%Vor% Im ersten Fall weise ich einem Funktionszeiger ein sehr einfaches Lambda zu, und es scheint zu funktionieren, wie ich es erwarten würde. Im zweiten Fall versuche ich, dem Lambda Zugriff auf den Wert von i
zu geben. Mein Verständnis von [i]()->int {
code }
ist, dass es eine namenlose Funktion definiert, die keine Argumente akzeptiert, ein int
zurückgibt und durch die Magie der C ++ 11-Einhörner den aktuellen Wert kennt Wert von i
. Ich würde erwarten, dass dieses Lambda als int(*)()
abrufbar sein sollte.
Es scheint, dass gcc 4.8.1 und 4.8.2 mit meiner Einschätzung nicht einverstanden sind (4.4.1 hat sich geweigert, die Angelegenheit überhaupt zu diskutieren).
Dies deutet darauf hin, dass der Typ dieses zweiten Lambda nicht mit dem Funktionszeiger kompatibel ist. Ich verstehe nicht, warum dies der Fall ist, da dieser Ausdruck als " int(*)()
" abrufbar sein sollte.
Wo hat mein Verständnis (oder die Einhörner) mich enttäuscht?
Aufrufbar mit Signatur int()
bedeutet nicht, dass es in eine int(*)()
konvertiert werden kann. Alles mit einem überladenen int operator()()
ist auf diese Weise aufrufbar.
Lambdas bilden mit einer solchen Überladung hübsche Moor-Standardklassen und wickeln sie dann in syntaktischen Zucker ein. (nicht wahr, aber wahr genug) 1
Stateless lambdas (diejenigen, die nichts fangen) kommen mit einem Bonus operator int(*)()
overload (oder operator Signature*
im Allgemeinen), aber das ist nur ein Bonus, kein Kern für ein Lambda.
Ein Funktionszeiger ist in der Praxis die Adresse, zu der die Ausführung springt, wenn Sie die Funktion aufrufen. Es gibt auch keinen Platz für einen Datenzeiger (um den Zustand Ihrer erfassten Variablen zu speichern). Theoretisch könnten Sie Platz für die Daten neben oder innerhalb des Ausführungscodes reservieren, aber viele Systeme blockieren das Markieren beschreibbarer Seiten als ausführbar sowie aus Sicherheitsgründen, was dieses System unpraktisch macht. Es gab Menschen, die diese Art von Erweiterung vorgeschlagen haben.
1 Wie bei vielen Dingen im C ++ - Standard werden Dinge in Bezug auf Verhalten und nicht auf Implementierung spezifiziert. Die meisten Funktionen von Lambdas können dupliziert werden, indem Mood-Standardklassen "automatisch geschrieben" für Sie implementiert werden, aber selbst dann muss der Compiler das nicht tun. Einige Lambda-Implementierungen (wie Stapelrahmenerfassung basierend auf [&]
lambdas) können nicht in der C ++ - Sprache implementiert werden.
Der C ++ Standard, Abschnitt 5.1.2 / 6, definiert, wie ein Lambda in einen (möglicherweise Vorlage-) Funktionszeiger umgewandelt werden kann.
Besonders:
Der Closure-Typ für einen nicht-generischen Lambda-Ausdruck ohne Lambda-Capture hat eine öffentliche nicht-virtuelle nicht-explizite Const-Konvertierung Funktion zum Zeiger auf Funktion mit C ++ Sprachverknüpfung (7.5) mit den gleichen Parametern und Rückgabetypen wie der Funktionsaufrufoperator des Schließungstyps. Der Wert, der von zurückgegeben wird Diese Konvertierungsfunktion soll die Adresse einer Funktion sein, die, wann aufgerufen, hat den gleichen Effekt wie der Aufruf der Funktion des Schließungstyps Anrufbediener
Da Ihr Lambda ein Capture hat, kann es nicht in einen Funktionszeiger umgewandelt werden.
Hinweis:
d. Folgendes gilt auch nicht:
%Vor%Sie können ein Lambda nicht in einen Funktionszeiger konvertieren, wenn es den Status hat. Wenn Sie zweimal überlegen, werden Sie sehen, dass ein gewöhnlicher Funktionszeiger keinen Zustand aus seiner Umgebung übertragen kann.
Also ist Ihr zweites Lambda nicht konvertierbar, aber das erste ist es, weil das erste Lambda ein Funktionszeiger ist.