Domanda

  

Eventuali duplicati
   Perché non posso avere un membro static const non integrale in una classe?

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
};

C'è qualche motivo per cui # 2, # 3, # 4 e # 5 sono illegali?

Credo di sapere il motivo per il 5 #: il compilatore ha bisogno di un "vero e proprio" oggetto stringa (dato che non è dotato di un tipo) e non può sostituire la mindlessy Five con "Hello" come se fosse #define Five "Hello". Ma se questo è il caso, non può il compilatore lasciare un suggerimento nei file obj e dire al linker per creare automaticamente un'istanza di string Five da qualche parte?

Per # 3 e # 4 e, soprattutto, # 2 (lol!) ... non posso davvero vedere alcuna ragione possibile! Float e double sono built-in tipi, proprio come int è! E a breve è solo una (forse) integer breve.


Modifica : Sto usando Visual Studio 2008 per compilarlo. Ho pensato che tutti i compilatori si comportavano lo stesso in questo caso, ma a quanto pare g ++ compila che bene (tranne # 5). Gli errori VS dà per che i frammenti sono:

    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
È stato utile?

Soluzione

L'int e il breve sono legali, e se il vostro compilatore non permette loro allora il compilatore è busto:

  

9.4.2 / 4: ... Se il membro di dati statico è di const integrale o const   tipo di enumerazione, la sua dichiarazione   la definizione di classe può specificare una    costante inizializzatore che deve essere un'espressione costante intera.

Credo che la ragione per cui galleggiante e doppie non sono trattati in modo speciale come costanti nella norma C ++, in modo che i tipi integrali sono, è che lo standard C ++ è diffidenti che le operazioni aritmetiche su float e double potrebbero essere sottilmente diverso sulla macchina compilazione, di quanto lo siano sulla macchina che esegue il codice. Per il compilatore di valutare un'espressione costante come (a + b), di cui ha bisogno per ottenere la stessa risposta che il runtime otterrebbe.

Questa non è tanto di un problema con interi - è possibile emulare aritmetica intera relativamente a buon mercato se diversa. Ma per il compilatore di emulare hardware in virgola mobile sul dispositivo di destinazione può essere molto difficile. Potrebbe anche essere impossibile, se ci sono diverse versioni del chip e il compilatore non sa che il codice verrà eseguito su. E questo è ancor prima di iniziare a fare scherzi con la modalità di arrotondamento IEEE. Così lo standard evitato che richiede, in modo che esso non ha dovuto definire quando e come la valutazione a tempo di compilazione possono differire dalla valutazione runtime.

Come cita Brian, C ++ 0x sta per affrontare questo con constexpr. Se ho ragione circa la motivazione originale, quindi presumibilmente 10 anni è stata abbastanza a lungo per lavorare attraverso le difficoltà nello specificare questa roba.

Altri suggerimenti

Sia Example::One e Example::Two devono compilare per voi, e effettivamente compilare per me nello stesso ambiente avete dichiarato (VS 2008).

Non credo Example::Three e Example::Four dovrebbe compilare a tutti in serie C ++, ma penso che ci sia un'estensione gcc che lo permette. Example::Five non deve compilare.

Si possono inizializzare in questo modo dopo la dichiarazione struct, in genere nel file di origine:

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

Questo è il modo più portatile per farlo, e il modo in cui mi sento di raccomandare a farlo anche se il compilatore permette di definire Example::Three e Example::Four nella dichiarazione.

Un'altra possibilità sarebbe quella di restituire semplicemente il valore di una funzione statica dello stesso tipo.

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

Questa risposta discute un possibile motivo pure.
Questa risposta discute come il moderno standard C ++ vi aiuterà tramite constexpr

# 1 e 2 sono compatibili con lo standard. Purtroppo, alcuni compilatori semplicemente non sono conformi. Ecco perché, ad esempio, i progettisti Boost dovuto introdurre le macro fastidiosi come BOOST_STATIC_CONSTANT per generare librerie portatili. Se non si desidera definire la costante in un file cpp, una soluzione portatile è di utilizzare un enum. Anche se, ovviamente, in questo caso si ha alcuna garanzia circa il tipo, e non è possibile utilizzare galleggianti.

  

In C ++ 98, solo i membri const statici di   tipi integrali possono essere inizializzate   in-class, e l'inizializzatore deve   essere un'espressione costante. Questi   restrizioni in modo che possiamo fare il   inizializzazione a tempo di compilazione.

In classe inizializzatori membri .

  

§9.4.2 membri dati statici

     

Se un membro di dati statico è di const tipo di enumerazione integrale o const, la sua dichiarazione nella definizione di classe de fi può   specificare un costante inizializzatore che deve essere un'espressione costante intera (5.19). In tal caso, può apparire l'organo   nelle espressioni costanti integrali. Il membro deve ancora essere definito in un ambito spazio dei nomi se viene utilizzato nel programma e   l'ambito dello spazio dei nomi de fi nizione non deve contenere un inizializzatore.

Sotto VS2008 ottengo il seguente errore:

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

E 'schifo, ma credo che basta non farlo se il compilatore rifiuta troppo ... Io non sono a conoscenza di questo essere una cosa specifica, ma sono sicuro che qualcuno mi correggerà ...

Re inizializzatori virgola mobile, spec C ++ 98 ha questo da dire (5.19):

  

letterali flottanti possono essere visualizzati solo se sono espressi da tipi integrali o enumerazione.

Come altri hanno trovato, i ++ vieta C standard inizializzazione dell'utente const statico con un valore in virgola mobile.

Almeno se ho capito bene, c'è una ragione abbastanza semplice per questo. C'è una sensazione (almeno parzialmente giustificata) che un'implementazione dovrebbe poter regolare la precisione in virgola mobile dinamicamente, quindi potrebbe non essere fino runtime che l'attuazione conosce il valore decimale esatto che sarebbe / sarà prodotta da un particolare punto floating letterale. In realtà, è anche possibile che questo potrebbe cambiare durante l'esecuzione.

Questa funzionalità esiste in hardware reale. Solo per esempio, Intel x86 ha un paio di bit nel registro di controllo punto il mobile che controllano l'accuratezza dei calcoli in virgola mobile. Per default, i calcoli vengono eseguiti sul lungo tipo doppia 80-bit, e arrotondati solo qualcosa come un galleggiante 64 bit doppio o 32 bit su richiesta. Questi bit nel registro possono essere modificati durante l'esecuzione, in modo (per esempio) "1.23" in un posto potrebbero inizializzare una variabile a un valore, mentre "1.23" in un'altra parte del programma (dopo che la precisione era stato regolato) potrebbe provocare in un (leggermente) diverso valore.

Almeno per quanto ne so, questa rimane una possibilità teorica, almeno sulla maggior parte delle macchine tipiche. Anche se l'hardware Intel permette la regolazione dinamica della FP precisione, non so di qualsiasi compilatore (nemmeno di Intel) che tenta di assumere un tale adeguamento in considerazione quando si traduce letterali FP (anche se il compilatore Intel ha almeno sostegno di una lunga 80-bit doppia tipo).

Come altri hanno fatto notare, il compilatore è rotto in alcuni casi. Ma non ho mai veramente capito il motivo per cui non è consentito per i tipi in virgola mobile, diverso da "Lo standard dice così". Sembra che ci sia una buona ragione tecnica.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top