2015-10-12 16 views
9

Meine Frage bezieht sich auf Lambda-Bereich für die statischen Elementinitialisierer. Betrachten Sie den folgenden Test:Lambda-Bereich für statische Member-Initialisierer

#include <functional> 
#include <iostream> 

struct S { 
    static const std::function<void(void)> s_func; 
}; 

const std::function<void(void)> S::s_func = []() { 
    std::cout << "Hello from " << __PRETTY_FUNCTION__ << std::endl; 
}; 

int main(void) { 
    S::s_func(); 
    return 0; 
} 

gcc von 4,8 Start definiert die Lambda im Rahmen von S, so gibt das Programm etwas wie folgt aus:

Hello from S::<lambda()> 

(gcc-4.8.2 hat eine andere Definition für __FUNCTION__ & Co-Makros, aber dennoch wird das Lambda noch definiert innerhalb S)

Inzwischen gcc-4.7 Lambda im globalen Bereich definiert, so dass das Programm Ausgänge

Hello from <lambda()> 

Wahrscheinlich neuere gcc sind mehr standardkonform. Ich möchte jedoch fragen, ob der Standard diesen Aspekt tatsächlich spezifiziert oder ob er von der Implementierung abhängig ist.

aktualisieren: wie @ user5434961 vorgeschlagen, dass all __FUNCTION__ -alike Makros Implementierung abhängig ist, so ist es besser, sie in einem standardkonformen Test zu vermeiden. So, hier ist das Beispiel, das kompiliert werden kann, wenn ein Compiler solche lambdas innerhalb S Umfang definiert und bricht die Kompilierung anders:

#include <functional> 
#include <iostream> 

struct S { 
    static const std::function<void(void)> s_func; 
private: 
    static const int s_field; 
}; 

const std::function<void(void)> S::s_func = []() { 
    std::cout << "Hello from S::s_func. S::s_field = " << S::s_field << std::endl; 
}; 

const int S::s_field = 1; 

int main(void) { 
    S::s_func(); 
    return 0; 
} 
+0

Ich denke, Sie sollten 'S :: s_field' in nur 's_field' in dem aktualisierten Beispiel ändern? Ansonsten denke ich, es kompiliert immer, was der Umfang ist. – Lingxi

+0

Nun, da 'S :: s_field' privat ist, kann nicht aus dem globalen Bereich zugegriffen werden, so dass der Code die Kompilierung auf GCC-4.7 tatsächlich bricht – user3159253

+0

Ja, ja. Ich übersah das Private. – Lingxi

Antwort

7

Dieses Problem angesprochen wurde, bevor aber ich nicht den entsprechenden Fehlerbericht finden. Hier ist ein broken link für einen MSVC-Fehlerbericht, der angeblich eingereicht wurde (es ist immer noch nicht im Jahr 2015 behoben: Sie können es bei rise4fun testen). Es wurde jedoch irgendwo zwischen 4,7 und 4,8 für GCC festgelegt. Die relevante standardese verwendet dies als einen Fehler zu sichern ist:

[C++ 11, 9.4.2/2] Der Initialisierer Ausdruck in der Definition eines static Datenelement in dem Umfang seiner Klasse .

[C++ 11, 5.1.2/2] Die Auswertung eines Lambda-Ausdrucks ergibt einen prvalue temporary (12.2). Dieses temporäre Objekt wird als Closure-Objekt bezeichnet. Ein Lambda-Ausdruck darf nicht in einem nicht bewerteten Operanden erscheinen (Abschnitt 5).

[C++ 11, 5.1.2/3] Der Typ des lambda-Ausdruck (der auch der Art des Verschlusses Objekt ist) ist eine einzigartige, unnamed non-union Klassentyp - der so genannte Verschluss type - deren Eigenschaften werden im Folgenden beschrieben. Dieser Klassentyp ist kein Aggregat (8.5.1). Der Schließungstyp wird im kleinsten Blockbereich, Klassenbereich oder Namespacebereich deklariert, der den entsprechenden Lambda-Ausdruck enthält.

Zuvor

Why lambda in static initializer can't access private members of class in VC++2013?

C++11 lambdas can access my private members. Why?

Why is it not possible to use private method in a lambda?

4

Ich denke, es in den Klassenbereich sein sollte.Zitiert aus cppreference (Hervorhebung von dir):

Die Lambda-Expressionskonstrukte ein unbenannte prvalue temporäres Objekt einzigartigen unnamed non-union Nicht-Aggregat-Typ, als Verschluss bekannt, , die (für die Zwecke der ADL erklärt) im kleinsten Block Bereich, Klassenbereich oder Namespacebereich, der den Lambda Ausdruck enthält.

In der Out-of-line Definition von S::s_func, geben Sie in den Anwendungsbereich der SS:: der Zeit auftritt. Der Lambda-Ausdruck ist also im Klassenbereich S enthalten. Da der nähere Typ ein Mitglied von S ist, wird der Zugriff auf private Mitglieder von S gewährt.

+0

Vielen Dank und @ user5434961 für gleichermaßen hilfreiche Antworten. Ich habe seine Antwort als akzeptiert markiert, da sie etwas früher war als deine. – user3159253

+0

@ user3159253 Gern geschehen :) Die Antwort von user5434961 ist besser als meine für das Zitieren des Standarddokuments. – Lingxi

Verwandte Themen