Perché non riesco a inizializzare static
i membri dei dati in classe?
Lo standard C ++ consente di inizializzare solo i tipi di integrale costante statico o di enumerazione all'interno della classe. Questo è il motivo per cui a
è consentito inizializzare mentre altri no.
Riferimento:
C ++ 03 9.4.2 Membri dati statici
§4
Se un membro di dati statici è di tipo const integral o const enumeration, la sua dichiarazione nella definizione di classe può specificare un inizializzatore di costante che deve essere un'espressione di costante integrale (5.19). In tal caso, il membro può apparire in espressioni di costanti integrali. Il membro deve ancora essere definito in un ambito dello spazio dei nomi se viene utilizzato nel programma e la definizione dell'ambito dello spazio dei nomi non deve contenere un inizializzatore.
Cosa sono i tipi integrali?
C ++ 03 3.9.1 Tipi fondamentali
§7
I tipi bool, char, wchar_t e i tipi interi con segno e senza segno sono chiamati collettivamente tipi integrali.43) Un sinonimo di tipo integrale è tipo intero.
Nota:
43) Pertanto, le enumerazioni (7.2) non sono integrali; tuttavia, le enumerazioni possono essere promosse a int, unsigned int, long o unsigned long, come specificato in 4.5.
Soluzione:
È possibile utilizzare il trucco enum per inizializzare un array all'interno della definizione della classe.
class A
{
static const int a = 3;
enum { arrsize = 2 };
static const int c[arrsize] = { 1, 2 };
};
Perché lo Standard non lo consente?
Bjarne lo spiega appropriatamente qui :
Una classe è tipicamente dichiarata in un file di intestazione e un file di intestazione è tipicamente incluso in molte unità di traduzione. Tuttavia, per evitare complicate regole del linker, C ++ richiede che ogni oggetto abbia una definizione univoca. Questa regola sarebbe infranta se C ++ consentisse la definizione in classe di entità che dovevano essere archiviate in memoria come oggetti.
Perché sono static const
consentiti solo tipi integrali ed enumerazioni in classe?
La risposta è nascosta nella citazione di Bjarne, letta attentamente,
"C ++ richiede che ogni oggetto abbia una definizione univoca. Quella regola sarebbe infranta se C ++ consentisse la definizione in classe di entità che dovevano essere archiviate in memoria come oggetti."
Notare che solo gli static const
interi possono essere trattati come costanti del tempo di compilazione. Il compilatore sa che il valore intero non cambierà in qualsiasi momento e quindipuò applicare la sua magia e applicare ottimizzazioni, il compilatore semplicemente integra tali membri della classe cioè non sono più archiviati in memoria, poiché viene rimossa la necessità di essere archiviati in memoria , fornisce a tali variabili l'eccezione alla regola menzionata da Bjarne.
È interessante notare che anche se i static const
valori integrali possono avere l'inizializzazione in classe, non è consentito prendere l'indirizzo di tali variabili. Si può prendere l'indirizzo di un membro statico se (e solo se) ha una definizione fuori classe. Ciò convalida ulteriormente il ragionamento sopra.
Gli enum sono consentiti perché i valori di un tipo enumerato possono essere utilizzati laddove sono previsti int. vedere la citazione sopra
Come cambia questo in C ++ 11?
C ++ 11 allenta la restrizione in una certa misura.
C ++ 11 9.4.2 Membri dati statici
§3
Se un membro dati statico è di tipo letterale const, la sua dichiarazione nella definizione della classe può specificare un inizializzatore di parentesi graffa o uguale in cui ogni clausola di inizializzazione che è un'espressione di assegnazione è un'espressione costante. Un membro di dati statici di tipo letterale può essere dichiarato nella definizione della classe con il constexpr specifier;
se è così, la sua dichiarazione deve specificare un inizializzatore di parentesi graffa o uguale in cui ogni clausola di inizializzazione che è un'espressione di assegnazioneè un'espressione costante. [Nota: in entrambi i casi, il membro può apparire in espressioni costanti. —End note] Il membro deve ancora essere definito in un ambito dello spazio dei nomi se viene utilizzato nel programma e la definizione dell'ambito dello spazio dei nomi non deve contenere un inizializzatore.
Inoltre, C ++ 11 vi permetterà (§12.6.2.8) un componente di dati non statico da inizializzare in cui è dichiarata (nella sua classe). Ciò significherà una semantica utente molto semplice.
Nota che queste funzionalità non sono state ancora implementate nell'ultimo gcc 4.7, quindi potresti ancora ricevere errori di compilazione.