2012-05-16 1 views
12

ho la seguente dichiarazione di alcuni membri static constmembri const Perché statici non possono apparire in un'espressione costante come 'interruttore'

.h

class MyClass : public MyBase 
{ 
public: 
    static const unsigned char sInvalid; 
    static const unsigned char sOutside; 
    static const unsigned char sInside; 
    //(41 more ...) 
} 

cpp

const unsigned char MyClass::sInvalid = 0; 
const unsigned char MyClass::sOutside = 1; 
const unsigned char MyClass::sInside = 2; 
//and so on 

A un certo punto voglio usare quei valori in un interruttore come:

unsigned char value; 
... 
switch(value) { 
    case MyClass::sInvalid : /*Do some ;*/ break; 
    case MyClass::sOutside : /*Do some ;*/ break; 
    ... 
} 

Ma ho il seguente errore del compilatore: errore: "MyClass :: sInvalid" non può apparire in un'espressione costante.

Ho letto altro switch-non-può-essere-costante-roba e non ho trovato una risposta per me dal momento che non capisco perché quelli static const unsigned char non sono un'espressione costante.

Sto utilizzando gcc 4.5.

risposta

17

I problemi che vedete sono dovuti al fatto che questo

static const unsigned char sInvalid; 

non può essere un momento della compilazione espressione costante, dal momento che il compilatore non conosce il suo valore. Inizializzali nell'intestazione in questo modo:

class MyClass : public MyBase 
{ 
public: 
    static const unsigned char sInvalid = 0; 
    ... 

e funzionerà.

+0

-1 per errore. È necessario specificare che l'inizializzazione dovrebbe essere ** all'interno ** della definizione della classe, non solo dell'intestazione.Se li inizializzi nell'intestazione, ma al di fuori della classe, riceverai errori di collegamento. –

+0

@LuchianGrigore: OK, l'ho chiarito. – jpalecek

+4

+1 per una soluzione valida, ma continuo a pensare che un enum è meglio qui. –

9

I valori sono in effetti const, ma non sono costanti in fase di compilazione.

Una condizione switch A è risolta in fase di compilazione, non in fase di esecuzione. È possibile inizializzare sInvalid per qualsiasi valore, purché sia ​​una sola volta e lo switch non lo saprebbe mai fino all'ora di esecuzione.

Sembra che tu stia meglio utilizzando enum s invece di static costanti. Oltre al fatto che avrebbe funzionato, sembra più appropriato dal punto di vista del design.

+0

Grazie per la tua preziosa spiegazione! Enum è stata la mia prima scelta, ma sto usando quelle costanti altrove in operazioni di bite-wise e nei grandi contenuti di array, ho davvero bisogno che siano "char unsigned". Non ho mai trovato un modo per farlo funzionare correttamente senza usare i tipi 'char unsigned' espliciti. L'uso di Enum predefinito e il cast su 'unsigned char' ovunque rendono il codice così non leggibile da permettermi di utilizzare questa soluzione. – vrince

+0

puoi spiegare la differenza tra una costante e una costante in fase di compilazione? (o il link a una spiegazione?) – dbliss

2

È possibile utilizzare il trucco enum per rendere costanti compilarli in tempo:

class MyClass 
{ 
public: 
    enum { 
     sInvalid, 
     sOutside, 
     sInside, 
     //(41 more ...) 
    }; 
}; 

Nel codice, è comunque possibile utilizzare l'enumerazione per assing a unsigned char, qualcosa di simile:

int main(int argc, char *argv[]) 
{ 
    unsigned char buf[32]; 
    buf[0] = MyClass::sInvalid; //int to unsigned char 
    return buf[0]; //Cast back to int (and avoid a warning a -Wall) 
} 

E utilizzare MyClass::sInvalid nelle dichiarazioni swith.

+0

Sì, ho davvero bisogno che siano 'char unsigned 'e non sono riuscito a creare' enum MyEnum: unsigned char' con tutte le versioni del compilatore che stiamo usando. – vrince

+0

Switch non importa. Vedi la mia modifica, compila con g ++ 4.6.1 -Wall – ixe013