2013-10-13 7 views
8

Ich spiele gerade mit C++ 11 Lambdas und fand ein Beispiel, das ich nicht verstehen kann. Gemäß dem Standard:Nicht lokale Lambda und Capturing-Variablen - was bedeutet "Block Scope" bedeutet

A lambda-expression whose smallest enclosing scope is a block scope (3.3.3) is a local lambda expression; any other lambda-expression shall not have a capture-list in its lambda-introducer

so, habe ich triviales Beispiel:

int a = 10; 
auto x = [a] { return 1;}; 
int main() { 
    int k = 5; 
    auto p = [k]{ return k; }; 
    return 0; 
} 

Der Code in ideone: http://ideone.com/t9emu5

Ich hatte erwartet, dass dieser Code aufgrund der Erfassung Variable nicht kompiliert werden in Nicht-Block-Bereich (oder zumindest denken, dass der Auto X = ... Teil nicht im Block-Bereich ist). Aber der Code kompiliert - ist es ok?

Wenn es in Ordnung ist - was ist der Block Umfang?

(Ich bin nicht sicher, welche Compiler-Version verwende ich zur Zeit, weil ich nur Zugriff auf ideone Website.

Dank für das zu erklären!

+0

also, welcher Umfang ist nicht-Block-Bereich? – matekm

+1

@DanielFrey Huh? Ein Block ist eine zusammengesetzte Anweisung und ein Namespace ist sicherlich kein Block. Siehe [basic.scope.block]/1 und [stmt.block] – dyp

+0

@DyP Sorry, ich war verwirrt. Du hast vollkommen recht! –

Antwort

12

Es sieht wie folgt aus einer Compiler-Erweiterung ist. G ++ 4.8 0,1 kompiliert diese, während eine Warnung zu geben:

warning: capture of variable ‘a’ with non-automatic storage duration [enabled by default]

Klirren ++ 3.4 nicht kompilieren dies:

error: 'a' cannot be captured because it does not have automatic storage duration

beziehen sich sowohl auf [expr.prim.lambda]/10

The identifiers in a capture-list are looked up using the usual rules for unqualified name lookup (3.4.1); each such lookup shall find a variable with automatic storage duration declared in the reaching scope of the local lambda expression.

Es sie zusätzlich nicht überprüfen Sie die umschließenden Umfang der Lambda scheint, kann ich mir vorstellen, es überflüssig wäre (es keine Namen von Variablen sind mit automatischer Speicherdauer im Nicht-Block/Namespace-Bereich).


Ein Block Umfang wird in [basic.scope.block]/1

A name declared in a block (6.3) is local to that block; it has block scope.

und ein Block definiert ist wie folgt definiert:

So that several statements can be used where one is expected, the compound statement (also, and equivalently, called “block”) is provided.

     compound-statement:
         {statement-seqopt}

So haben Sie Recht, dass Ihre global deklariert Lambda ist nicht in einem Block Umfang.

+0

vielen Dank! – matekm

+0

Hinzufügen: Sie können GCC ablehnen, indem Sie das Kompilierungsflag '-pedantic-errors' (zusätzlich zu' -std = C++ 11') verwenden, was ich empfehle (und '-Wall -Wextra 'auch). In Ideone können Sie keine Compiler-Optionen angeben, sondern z. [Coliru] (http://coliru.stacked-crooked.com/) tut es auch ([GCC Explorer] (http://gcc.godbolt.org/), aber es kompiliert nur (und zeigt die Assembly-Ausgabe an), tut es nicht 't Link und run). (Siehe zum Beispiel http://isocpp.org/get-started für mehr Online-C++ - Compiler.) –

+0

@ gx_ Das scheint falsch zu sein.Ich kompiliere mit "-Wall -Wextra -Wpedantic" und wurde nie über diesen Fehler in meinem Code (der wahrscheinlich aus dem Verschieben des Lambda aus einem lokalen Bereich resultiert), über 'g ++' Version 5 und jetzt 6.1. Hinzufügen "-pedantic-Fehler", eher nicht überraschend, ändert nichts daran. 'g ++' warnt mich einfach nicht. Ich denke, ich muss 'clang ++' für eine zweite Meinung öfter fragen ... seufzen –