Frage

  

Mögliche Duplizieren
   Warum kann ich nicht haben ein nicht-integrales static const Mitglied in einer Klasse?

struct Example
{
    static const int One = 1000; // Legal
    static const short Two = 2000; // Illegal
    static const float Three = 2000.0f; // Illegal
    static const double Four = 3000.0; // Illegal
    static const string Five = "Hello"; // Illegal
};

Gibt es einen Grund, für die # 2, # 3, # 4 und # 5 illegal sind?

Ich glaube, ich kenne den Grund für # 5: der Compiler ein „echtes“ String-Objekt muss (da es keine in Art gebaut ist) und kann mindlessy nicht Five mit "Hello" ersetzen, als ob es #define Five "Hello" war. Aber wenn das der Fall ist, kann nicht der Compiler einen Hinweis in den OBJ-Dateien zu lassen und den Linker sagen, um automatisch eine Instanz string Five irgendwo erstellen?

# 3 und # 4 und insbesondere # 2 (lol!) ... Ich kann nicht wirklich einen möglichen Grund sehen! Floats und doubles sind integrierte Typen, wie int ist! Und kurz ist nur eine (möglicherweise) kürzer ganze Zahl ist.


Bearbeiten : Ich Visual Studio 2008 bin mit ihm zu kompilieren. Ich dachte, alle Compiler die gleichen in diesem Fall verhalten haben, aber anscheinend g ++ kompiliert, dass feine (außer # 5). Die Fehler VS für diesen Schnipsel gibt, sind:

    error C2864: 'Example::Two' : only static const integral data members can be initialized within a class
    error C2864: 'Example::Three' : only static const integral data members can be initialized within a class
    error C2864: 'Example::Four' : only static const integral data members can be initialized within a class
    error C2864: 'Example::Five' : only static const integral data members can be initialized within a class
War es hilfreich?

Lösung

Der int und die kurz sind legal, und wenn Ihr Compiler nicht erlaubt sie dann Compiler ist pleite:

  

9.4.2 / 4: ... Wenn das statische Datenelement aus const integral oder const   Aufzählungstyp, ihre Erklärung in   die Klassendefinition kann eine angeben    Konstant initializer , das ist integraler konstanter Ausdruck sein.

Ich glaube, dass der Grund, dass die Schwimmer und Doppel sind nicht speziell als Konstanten in der C behandelt ++ Standard, in der Weise, dass integrale Typen sind, ist, dass der C ++ Standard vorsichtig ist, dass die arithmetische Operationen auf float und double subtil sein könnte andere auf dem Kompilieren Maschine, als sie auf der Maschine sind, die den Code ausführt. Für die Compiler einen konstanten Ausdruck wie (a + b) zu bewerten, muss es die gleiche Antwort bekommt, dass die Laufzeit bekommen würde.

Dies ist nicht so sehr ein Problem mit ints - Sie Integer-Arithmetik emulieren können relativ billig, wenn es unterscheidet. Aber für den Compiler zu emulieren Gleitkomma-Hardware auf dem Zielgerät kann sehr schwierig sein. Es könnte sogar unmöglich sein, wenn es verschiedene Versionen des Chips und der Compiler nicht weiß, welche der Code laufen. Und das ist, noch bevor Sie mit dem IEEE-Rundungsmodus starten Messing. So ist der Standard, der es vermied erfordern, so dass es nicht definieren musste, wann und wie Kompilierung-Auswertung von Laufzeitauswertung unterscheiden können.

Wie Brian erwähnt, C ++ 0x wird dies mit constexpr adressieren. Wenn ich mich recht über die ursprüngliche Motivation bin, dann vermutlich 10 Jahre hat sich durch die Schwierigkeiten der Arbeit lange genug dieses Zeug in angeben.

Andere Tipps

Sowohl Example::One und Example::Two sollten für Sie zusammenstellen, und sie kompilieren in der Tat für mich in der gleichen Umgebung, die Sie angegeben (VS 2008).

Ich glaube nicht, Example::Three und Example::Four sollte überhaupt in Standard C ++ kompilieren, aber ich denke, es gibt eine gcc-Erweiterung, die es erlaubt. Example::Five sollte nicht kompiliert werden.

Sie können sie so nach der Strukturdeklaration initialisieren möchten, in der Regel in der Quelldatei:

const float Example::Three = 2000.0f;
const double Example::Four = 3000.0;
const string Example::Five = "Hello";

Dies ist die tragbare Art und Weise, es zu tun, und die Art, wie ich empfehlen würde es, selbst wenn Ihr Compiler tun können Sie Example::Three und Example::Four in Ihrer Erklärung definieren.

Eine andere Möglichkeit wäre, einfach den Wert von einer statischen Funktion des gleichen Typs zurück.

struct Example
{
    //...
    static double Four() { return  = 3000.0; }
    //...
};

Diese Antwort bespricht ein möglicher Grund auch.
diese Antwort erläutert, wie die bevorstehende C ++ Standard wird dazu beitragen, über constexpr

# 1 und 2 sind mit dem Standard konform. Leider entsprechen einige Compiler einfach nicht. Deshalb, zum Beispiel der Boost-Designer ärgerlich Makros einführen mußten wie BOOST_STATIC_CONSTANT portable Bibliotheken zu erzeugen. Wenn Sie nicht die Konstante in einer CPP-Datei definieren möchten, eine tragbare Abhilfe ist ein enum zu verwenden. Obwohl offensichtlich in diesem Fall haben Sie keine Garantie über die Art, und Sie können nicht schwimmen verwenden.

  

In C ++ 98, nur statische const Mitglieder   Integral-Typ kann initialisiert werden   in-Klasse und der Initialisierer muss   sein ein konstanter Ausdruck. Diese   Einschränkungen sicherzustellen, dass wir das tun können,   Initialisierung bei der Kompilierung-Zeit.

Siehe In-Class-Mitglied initializers .

  

§9.4.2 Statische Datenelemente

     

Wenn ein statisches Datenelement ist von const integral oder const Aufzählungstyp, seine Deklaration in der Klassendefinition kann   geben eine Konstant Initialisierer die einen integrierenden konstanter Ausdruck sein wird (5,19). In diesem Fall kann das Element erscheinen   in integralen konstanten Ausdrücken. Das Mitglied wird nach wie vor de fi in einem Namespace Umfang definiert sein, wenn sie im Programm verwendet wird, und   der Namespace Umfang De fi nition stellt keinen Initialisierer enthält.

Unter VS2008 ich die folgende Fehlermeldung erhalten:

1>.\Weapon Identification SystemDlg.cpp(223) : error C2864: 'Example::Three' : only static const integral data members can be initialized within a class
1>.\Weapon Identification SystemDlg.cpp(224) : error C2864: 'Example::Four' : only static const integral data members can be initialized within a class
1>.\Weapon Identification SystemDlg.cpp(225) : error C2864: 'Example::Five' : only static const integral data members can be initialized within a class

Es saugt aber ich denke, man muss es einfach nicht, wenn Ihr Compiler zu weigert ... Ich bin mir nicht bewusst diese eine spec Sache zu sein, aber ich bin sicher, dass jemand mich korrigieren ...

Re die Gleitkomma initializers, die C ++ 98 spec hat dies zu sagen, (5.19):

  

Schwimm Literale kann nur angezeigt, wenn sie integral oder Aufzählungstypen gegossen werden.

Wie andere haben gefunden, die C ++ Standard verbietet ein statisches const Element mit einem Fließkommawert initialisiert wird.

Wenigstens wie ich es verstehe, gibt es einen ziemlich einfachen Grund dafür. Es ist ein Gefühl, (zumindest teilweise gerechtfertigt), dass eine Implementierung erlaubt sein soll, die Gleitkommagenauigkeit dynamisch anzupassen, so dass es nicht erst zur Laufzeit sein könnte, dass die Umsetzung den genauen Fließkommawert kennt, / würde von einem bestimmten Floating-Point hergestellt wird wörtlich zu nehmen. In der Tat, es ist sogar möglich, dass diese während der Ausführung ändern könnten.

Diese Fähigkeit ist in realer Hardware existiert. Nur zum Beispiel hat die Intel x86 ein paar Bits in dem Gleitkomma-Steuerregister, das die Genauigkeit von Gleitkomma-Berechnungen zu steuern. Standardmäßig werden die Berechnungen auf dem 80-Bit getan langen Doppeltyp und nur gerundet auf so etwas wie ein 64-Bit-Doppel oder 32-Bit-Float auf Anfrage. Diese Bits in dem Register während der Ausführung geändert werden, so dass (zum Beispiel) „1,23“ an einer Stelle könnte eine Variable auf einen Wert, während „1,23“ in einem anderen Teil des Programms initialisiert wird (nachdem die Präzision hatte eingestellt worden ist) könnte dazu führen, in einem (leicht) unterschiedlichen Wert.

Mindestens so weit ich weiß, bleibt dies eine theoretische Möglichkeit, zumindest bei den meisten typischen Maschinen. Obwohl die Intel-Hardware dynamische Anpassung der FP Präzision ermöglicht, weiß ich nicht von jedem Compiler (auch nicht von Intel), dass Versuche, eine solche Anpassung zu berücksichtigen, wenn FP Literale übersetzen (obwohl Compiler von Intel tut zumindest Unterstützung eine 80-Bit lange Doppel-Typ).

Wie andere haben darauf hingewiesen, Ihr Compiler wird in einigen Fällen gebrochen. Aber ich habe nie wirklich verstanden, den Grund, warum es nicht für Gleitkommatypen erlaubt ist, anders als „Der Standard sagt so“. Es scheint kein guter technischer Grund.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top