Eine besondere Eigenschaft der Lambda-Ausdrücke von c ++ ist die Erfassung der Variablen in dem Bereich, in dem sie deklariert sind. Zum Beispiel kann ich eine deklarierte und initialisierte Variable c in einer Lambda-Funktion verwenden, auch wenn 'c' nicht als Argument gesendet wird, sondern von '[]':
%Vor%Die erwartete Ausgabe ist also 10. Das Problem tritt auf, wenn mindestens zwei Variablen, die eine erfasst und die andere als Argument gesendet wird, den gleichen Namen haben:
%Vor% Ich denke, dass der 2011-Standard für C ++ besagt, dass die eingefangene Variable Vorrang vor den Argumenten des Lambda-Ausdrucks hat, wenn die Namen übereinstimmen. Bei der Kompilierung des Codes mit GCC 4.8.1 unter Linux ist die Ausgabe, die ich erhalte, die erwartete, 5
. Wenn ich denselben Code mit der apple-Version des clang-Compilers (clang-503.0.40, der mit Xcode 5.1.1 auf Mac OS X 10.9.4 gelieferten) kompiliere, bekomme ich die andere Antwort, 3
.
Ich versuche herauszufinden, warum das passiert; ist es nur ein Apple-Compiler-Bug (wenn der Standard für die Sprache wirklich besagt, dass das eingefangene "c" Vorrang hat) oder etwas Ähnliches? Kann dieses Problem behoben werden?
BEARBEITEN
Mein Lehrer hat eine E-Mail an den GCC-Helpdesk geschickt und sie haben geantwortet, dass es sich eindeutig um einen Fehler des GCC-Compilers handelt, und melden Sie ihn Bugzilla. Also ist Clangs Verhalten das Richtige!
Aus dem C ++ 11 Standard, 5.1.2 "Lambda-Ausdrücke" [expr.prim.lambda] # 7:
Die lambda-expression compound-Anweisung liefert den function-body (8.4) des Funktionsaufrufoperators. aber zum Zwecke der Namenssuche (3.4), Bestimmen des Typs und Wertes vonthis
(9.3.2) und Transformieren von id-expressions s Verweisen auf nicht statische Klassenmitglieder in Zugriffsberechtigungen für Klassenmitglieder mit(*this)
(9.3.1), die compound-Anweisung wird im Zusammenhang mit dem Lambda-Ausdruck betrachtetAuch von 3.3.3 "Block scope" [basic.scope.local] # 2:
Der potenzielle Geltungsbereich eines Funktionsparameternamens (einschließlich einer Angabe in einem lambda-declarator ) oder von Eine funktions-lokale vordefinierte Variable in einer Funktionsdefinition (8.4) beginnt an ihrem Deklarationspunkt.Namen in einer Aufnahmeliste sind keine Deklarationen und haben daher keinen Einfluss auf die Namenssuche. In der Erfassungsliste können Sie nur die lokalen Variablen verwenden. es führt ihre Namen nicht in den Geltungsbereich des Lambda ein. Beispiel:
%Vor%Da die Parameter zu einem Lambda in einem inneren Blockbereich liegen und da die Namenssuche im Kontext des Lambda-Ausdrucks erfolgt (nicht etwa der generierten Klasse), verbergen die Parameternamen tatsächlich die Variablennamen die umschließende Funktion.
Nach meinem Verständnis der folgenden Punkte des c ++ 11 Standards:
5.1.2 Lambda-Ausdrücke
3 Der Typ des Lambda-Ausdrucks (der auch der Typ des Closure-Objekts ist) ist ein eindeutiger, unbenannter Nicht-Vereinigungsklassen-Typ - genannt der Verschlusstyp - dessen Eigenschaften im Folgenden beschrieben werden.
...
5 Der Closure-Typ für einen Lambda-Ausdruck hat einen öffentlichen Inline-Funktionsaufrufoperator (13.5.4), dessen Parameter und Rückgabetyp sind beschrieben durch die parameter-deklaration-Klausel des Lambda-Ausdrucks und Trailing-Return-Typ jeweils. Dieser Funktionsaufruf-Operator ist deklariert const (9.3.1) genau dann, wenn der Lambda-Ausdruck Auf die Parameter-Deklarationsklausel folgt keine Änderbarkeit.
...
14 Für jedes durch copy erfasste Objekt wird ein nicht benanntes nicht statisches Datenelement im Verschlusstyp
deklariert
Ein Lambda-Ausdruck wie dieser ...
%Vor%... entspricht ungefähr einer Klasse / Struktur wie folgt:
%Vor%Ich würde also erwarten, dass der Parameter das erfasste Mitglied ausblenden würde.
BEARBEITEN:
In Punkt 14 aus dem Standard (oben zitiert) scheint das aus der erfassten Variablen erstellte Datenelement * zu sein. unbenannt * . Der Mechanismus, nach dem es referenziert wird, scheint unabhängig von den normalen Bezeichner-Lookups zu sein:
17 Jeder ID-Ausdruck, der eine odr-use (3.2) einer durch copy erfassten Entität ist, wird in einen Zugriff auf das entsprechende unbenannte Datenelement der Schließungstyp.
Es ist unklar, ob ich beim Lesen des Standards entscheiden sollte, ob diese Transformation Vorrang vor der Parametersymbolsuche haben soll.
Vielleicht sollte dies also als UB (undefiniertes Verhalten) markiert werden?