2015-09-27 1 views
5

Soweit ich weiß, können Sie nur statische const Mitglieder in der gleichen Zeile ihrer Deklaration if they are integral types initialisieren. Allerdings war ich noch in der Lage einige statische const zu initialisieren und verwenden verdoppelt:Falsche statische const Initialisierung, kompiliert und funktioniert

// compiles and works, values are indeed doubles 
struct Foo1{ 
    static const double A=2.5; 
    static const double B=3.2; 
    static const double C=1.7; 
}; 

// compiles, but values are cast to int 
struct Foo2{ 
    static const int A=2; 
    static const int B=3; 
    static const double C=B/A; //becomes 1 
}; 

// does not compile, Foo3::B cannot appear in a constant-expression 
struct Foo3{ 
    static const int A=2; 
    static const double B=3; 
    static const double C=A/B; 
}; 

// does not compile, a cast to a type other than an integral or enumeration 
// cannot appear in a constant-expression 
struct Foo4{ 
    static const int A=2; 
    static const int B=3; 
    static const double C=(double)A/B; 
}; 

foo2 kompiliert aber foo2 :: C 1 wird, vielleicht wird es als int behandelt, wie es numerisch ist. Foo3 und Foo4 kompilieren nicht wie erwartet. Allerdings verstehe ich nicht, warum Foo1 sowohl kompiliert als auch korrekt funktioniert. Wird diese spezifische Verwendung akzeptiert? Liegt es an einer Optimierung? (Ich habe versucht mit -O1 und -O0)

Hinweis: GNU 5.2.0 mit cmake verwenden und den Standard auf C++ 98 setzen. Die Umstellung auf C++ 11 funktioniert einwandfrei (das heißt, kompiliert nicht und fragt, ob diese Mitglieder zu conexpr wechseln sollen).

+1

Fügen Sie den '-pedantic' Schalter hinzu, dann gcc wird sich sogar über' Foo1' beschweren. http://melpon.org/wandbox/permlink/o35cpEXlgMedfvMT – dyp

Antwort

11

Der Foo1 Fall ist in der Tat nicht konforme und wenn wir -std=c++98 -pedantic gcc bauen mit warnt wie folgt (see it live):

error: floating-point literal cannot appear in a constant-expression 
static const double A=2.5; 
        ^
warning: ISO C++ forbids initialization of member constant 'Foo1::A' of non-integral type 'const double' [-Wpedantic] 

Während ohne -pedantic Kompilieren ergeben keine Fehler oder Warnung (see it live)

Also muss dies eine Erweiterung sein und wenn wir clang mit -std=C++98 -pedantic verwenden, sehen wir diese Nachricht:

warning: in-class initializer for static data member of type 'const double' is a GNU extension [-Wgnu-static-float-init] 
static const double A=2.5; 
        ^~~~ 

die scheint zu bestätigen, dass dies eine Erweiterung ist.

Diese Beschränkung auf Fließkomma wurde in C++ 11 beibehalten, um kompatibel mit C++ 03 zu bleiben und eine konsistente Verwendung von consExpr zu fördern, siehe: Constant expression initializer for static class member of type double.

Dies ist auch der Fall für Foo2C Initialisierung als Erweiterung erlaubt ist, wird das Ergebnis der Division int sein, da der Typ des Ergebnisses von der Art des Operanden hängt und hängt nicht davon ab, was Sie zuweisen es zu.

aktualisieren

Dies ist ein depreciated extension:

G ++ statische Datenelemente von const Gleitkommatyp ermöglicht mit einem Initialisierer in einer Klassendefinition zu erklären. Der Standard lässt nur Initialisierer für statische Elemente von Const-Integraltypen und Const-Aufzählungstypen zu, sodass diese Erweiterung veraltet ist und aus einer zukünftigen Version entfernt wird.

Es gibt eine detailliertere gcc bug report, die die Gültigkeit der Erweiterung und andere damit zusammenhängende Probleme diskutiert.

Es schien seltsam, dass die Verwendung -pedantic allein ausreichend war, um dies in einen Fehler zu verwandeln, gibt es eine gcc bug report that covers that.