Warum verhält sich dieses C ++ 11 Lambda nicht so, wie ich es erwarte?

8

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.

%Vor%

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?

    
John Auld 18.08.2014, 01:43
quelle

3 Antworten

2

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.

    
Yakk 18.08.2014, 01:55
quelle
9

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:

  • Achten Sie darauf, dass Captures implizit oder standardmäßig mit einem lamdba verbunden sein können.

d. Folgendes gilt auch nicht:

%Vor%

Live-Demo

    
quantdev 18.08.2014 01:57
quelle
2

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.

    
Germán Diago 18.08.2014 02:09
quelle

Tags und Links