2010-03-16 14 views
55

Ho una classe che essenzialmente contiene solo un gruppo di definizioni costanti utilizzate attraverso la mia applicazione. Per qualche ragione, però, long s compilano ma float s non:Perché non sono permessi i flo statici?

class MY_CONSTS 
{ 
public : 
    static const long LONG_CONST = 1;  // Compiles 
    static const float FLOAT_CONST = 0.001f; // C2864 
}; 

dà il seguente errore:

1>c:\projects\myproject\Constant_definitions.h(71) : error C2864: 'MY_CONSTS::FLOAT_CONST' : only static const integral data members can be initialized within a class 

mi sto perdendo qualcosa?

+3

possibile duplicato di [Perché non è possibile avere un membro const const non integrale in una classe?] (Http://stackoverflow.com/questions/370283/why-cant-i-have-a-non- integral-static-const-member-in-a-class) –

risposta

53

Per rispondere alla domanda effettiva è stato chiesto: "perché lo standard dice così".

Solo le variabili di tipo statico, costante, integrale tipi (incluse le enumerazioni) possono essere inizializzate all'interno di una dichiarazione di classe. Se un compilatore supporta l'inizializzazione in linea dei float, è un'estensione. Come altri hanno sottolineato, il modo di gestire variabili statiche, costanti e non integrali è di definirle e inizializzarle nel corrispondente file sorgente della classe (non nell'intestazione).

C++ Sezione standard 9.2 "Classe Membri" punto 4:

A member-declarator can contain a constant-initializer only if it declares a static member (9.4) of const integral or const enumeration type, see 9.4.2.

Sezione 9.4.2 voce "membri di dati static" 2:

If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions. The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer.

+10

Infatti. Bene che C++ 0x supporterà gli inizializzatori float in classe tho. –

+3

Un altro buon modo sarebbe quello di fare in modo che una funzione restituisca quel valore. Il vantaggio è che il valore è visibile al compilatore (che può integrare la funzione). Una definizione in -cpp non espone il valore ad altre TU. –

+1

C'è un altro vantaggio nell'approccio alla funzione: si evita il "fiasco dell'ordine di inizializzazione statico" che può accadere se si tenta di inizializzare valori statici utilizzando altri valori statici di altre unità di compilazione (anche se questo probabilmente non si verifica con tipi predefiniti come galleggiante). –

34

Si dovrebbe inizializzare nel corpo di uno dei tuoi file CPP:

class MY_CONSTS 
{ 
public : 
    static const long LONG_CONST = 1;  // Compiles 
    static const float FLOAT_CONST; 
}; 

const float MY_CONSTS::FLOAT_CONST = 0.001f; 
+3

Alcuni compilatori si aspettano ancora che tu abbia un'altra riga nel file cpp per definire lo spazio per 'LONG_CONST':' const long MY_CONSTS :: LONG_CONST; 'Nota che non 'ripeti l'inizializzazione qui. –

+3

@Adrian: la differenza è che questi compilatori sono danneggiati. – sbi

+1

@sbi: Cosa? L'inizializzazione in linea di un membro statico non elimina la necessità di una definizione. –

3

che dire:

class MY_CONSTS 
{ 
public : 
    static const long LONG_CONST; 
    static const float FLOAT_CONST; 
}; 

const long MY_CONSTS::LONG_CONST = 1; 
const float MY_CONSTS::FLOAT_CONST = 0.001f; 

(anche se, non posso dare alcuna spiegazione di questo caso specifico ...)

19

Vedere Stroustrup's explanation. Preventivo rilevante:

A class is typically declared in a header file and a header file is typically included into many translation units. However, to avoid complicated linker rules, C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects. See D&E for an explanation of C++'s design tradeoffs.

+12

Questo in realtà non risponde alla domanda. Perché un 'long' può essere inizializzato e un' float' no? Presumibilmente un 'long' non ha bisogno 'di essere immagazzinato in memoria come [un oggetto]' ma un' float' fa? Come ha senso? La costante lunga – KitsuneYMG

+14

può essere inclusa nell'istruzione CPU (almeno sulle CPU Intel). Un float non può fare a meno di essere in memoria. Usando un leggero abuso di notazione, puoi dire che i lunghi possono essere inlineati e che i galleggianti non possono. –

3

Dallo standard 9.4.2/4

If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions. The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer.

E 5.19/1:

In several places, C + + requires expressions that evaluate to an integral or enumeration constant: as array bounds (8.3.4, 5.3.4), as case expressions (6.4.2), as bit-field lengths (9.6), as enumerator initializers (7.2), as static member initializers (9.4.2), and as integral or enumeration non-type template arguments (14.3). constant-expression: conditional-expression An integral constant-expression can involve only literals (2.13), enumerators, const variables or static data members of integral or enumeration types initialized with constant expressions (8.5), non-type template parameters of integral or enumeration types, and sizeof expressions. Floating literals (2.13.3) can appear only if they are cast to integral or enumeration types. Only type conversions to integral or enumeration types can be used. In particular, except in sizeof expressions, functions, class objects, pointers, or references shall not

8

La logica sotto la dicitura standard che altri hanno dato è la stessa per cui gli argomenti del modello non possono essere in virgola mobile. Per ottenere risultati coerenti è necessario che il compilatore implementa la stessa valutazione di quella eseguita in fase di compilazione e che può essere complicato per il cross-compilatore e nel caso in cui il programma giochi con la modalità di arrotondamento.

Dalla memoria, in C++ 0X, la nozione di espressione costante è stata estesa e quindi il codice sarebbe valido (ma non è specificato nel risultato di espressioni costanti in virgola mobile lo stesso quando viene valutato in fase di esecuzione o al momento della compilazione).

Problemi correlati