2012-02-26 14 views
20

Sto utilizzando un enumerato ambito per enumerare gli stati in una macchina a stati che sto implementando. Per esempio, diciamo qualcosa di simile:Equivalente di "utilizzo dello spazio dei nomi X" per le enumerazioni con ambito?

enum class CatState 
{ 
    sleeping, 
    napping, 
    resting 
}; 

Nel mio file cpp in cui mi definisco un tavolo transizione di stato, vorrei utilizzare qualcosa di equivalente a using namespace X in modo che io non ho bisogno di prefisso tutti i miei nomi degli stati con CatState::. In altre parole, mi piacerebbe utilizzare sleeping anziché CatState::sleeping. La mia tabella di transizione ha alcune colonne, quindi evitare il prefisso CatState:: manterrebbe le cose più compatte e leggibili.

Quindi, c'è un modo per evitare di dover digitare CatState:: tutto il tempo?


Sì, sì, io sono già consapevoli delle insidie ​​di using namespace. Se esiste un equivalente per enumerazioni fortemente tipizzate, prometto di usarlo solo in un ambito limitato nel mio file di implementazione cpp, e non per il male.

+0

Avete davvero bisogno di un 'enum class', o un' enum' do? – netcoder

+0

Originariamente era un semplice 'enum', ma sto passando il mio codice per usare le funzionalità di C++ 11. Mi piace l'idea di una sicurezza di tipo più forte con 'enum class'. –

risposta

11

Quindi, c'è un modo per evitare di dover digitare CatState:: tutto il tempo?

No. Proprio come non esiste un equivalente per dover digitare ClassName:: per membri di classe statici. Non puoi dire using typename ClassName e poi raggiungere la parte interna. Lo stesso vale per gli enum s fortemente tipizzati.

Naturalmente non è possibile utilizzare la sintassi enum class, utilizzando solo i normali enum s. Ma poi perdi forte digitazione.

Va notato che uno dei motivi per l'utilizzo di ALL_CAPS per le enumerazioni debolmente tipizzate era evitare conflitti di nome. Una volta che abbiamo un ambito completo e una digitazione forte, il nome di un enum è identificato in modo univoco e non può essere in conflitto con altri nomi. Essere in grado di portare questi nomi in ambito namespace potrebbe reintrodurre questo problema. Quindi probabilmente vorrai usare ancora ALL_CAPS per aiutare a chiarire i nomi.

+1

+1 Grazie. Stavo immaginando che l'enum forte sia qualcosa come uno spazio dei nomi, ma pensarlo come una (un po ') classe ha più senso ora. –

8

si potrebbe considerare l'utilizzo di un typedef per accorciare i nomi qualificati:

typedef CatState C; 

Oppure, se le colonne sono ripetitive in modo che essi possono essere generati facilmente, si potrebbe considerare l'utilizzo di una macro per generare ogni riga nella tabella, che può portare a un codice molto conciso (e più facile da leggere).

+0

Quindi stai dicendo che non esiste un equivalente di "utilizzo dello spazio dei nomi" per le enumerazioni? Se è così, allora un breve typedef mi sembra la soluzione migliore. –

+0

Non che io sappia, no. Potresti essere in grado di utilizzare una dichiarazione using per ogni enumeratore (ad es., Usando CatState :: sleeping ;, ecc.), Ma non ne sono sicuro al 100%. Se il codice è altamente ripetitivo, però, consiglio vivamente una macro. –

+0

+1 Ho finito per usare il tuo suggerimento typedef, ma Nicol ha dato la risposta diretta alla mia domanda. Vorrei poter accettare entrambe le risposte. –

2

La risposta di Nicol è corretta: il linguaggio è progettato per farti qualificare sempre gli enumeratori con ambito (tranne nello scope enum { } stesso).

Tuttavia, here is a technique Mi sono avvicinato per gli enumeratori "scoped" che sono senza ambito all'interno delle classi selezionate. Tecnicamente, gli enumeratori sono senza ambito, quindi convertiranno ancora implicitamente in int. (Non "fortemente tipizzato" come lo metti.) Tuttavia, nell'idioma sono accessibili usando l'operatore scope dopo un vero nome enum, quindi sintatticamente non c'è una differenza - e quindi richiede C++ 11.

#define IMPORTABLE_ENUM(TYPENAME, ...) \ 
\ 
struct import_ ## TYPENAME { \ 
    enum TYPENAME { \ 
     __VA_ARGS__ \ 
    }; \ 
}; \ 
\ 
typedef import_ ## TYPENAME :: TYPENAME TYPENAME; 

// usage: 
IMPORTABLE_ENUM (duck, huey, dewey, louie) 

duck d = duck::dewey; // can't use unscoped enumerators here 

struct duck_madness : private import_duck { // but inside a derived class 
    duck who_did_it() { return huey; } // qualification is unnecessary 
}; 
2

Mi piacerebbe anche avere questa possibilità e trovo la limitazione piuttosto fastidiosa.Di solito è meglio che il programmatore decida quali funzionalità desidera utilizzare. O scoping esplicito o il modo più conveniente. Se si limita il programmatore, o perderà l'intera funzionalità per comodità o inventerà brutte soluzioni alternative, come il seguente enum sicuro basato sul modello. Avrà un overhead quando compilato senza ottimizzazione.

template<class _Enum> 
class type_safe_enum 
{ 
private: 
    _Enum m_EnumValue; 
    operator int(); 
public: 
    inline operator _Enum() const { return m_EnumValue; } 
    inline void operator =(_Enum x) { m_EnumValue = x; } 
}; 

enum _MY_ENUM 
{ 
    Value1, 
    Value2 
}; 

enum _MY_ENUM2 
{ 
    Value3, 
    Value4 
}; 

typedef type_safe_enum<_MY_ENUM> MY_ENUM; 

void TestMyEnum() 
{ 
    MY_ENUM myEnum; 
    int x; 

    myEnum = Value1; // ok 
    // myEnum = Value3; // compilation error 
    // myEnum = 0; // compilation error 
    // x = myEnum; // compilation error 

} 
+1

Gli identificatori '_Enum' e altri' _ [A-Z] + 'portano a comportamenti non definiti, vedere [regole sui caratteri di sottolineatura] (http://stackoverflow.com/a/228797/673852). Vale a dire, 'Tutti gli identificatori che iniziano con un carattere di sottolineatura e una lettera maiuscola o un altro carattere di sottolineatura sono sempre riservati per qualsiasi uso. 'Se il programma dichiara o definisce un identificatore in un contesto in cui è prenotato <...>, il comportamento non è definito. – Ruslan

+0

Immagino che tu non sia del mondo Windows, altrimenti sapresti che MS viola quello standard con la maggior parte dei loro tag struct. Non ho detto, usa questo codice come è per il tuo progetto personale. Questi identificatori sono riservati in modo che i normali * programmatori abbiano regole che possono seguire e non entrano in conflitto con gli sviluppatori di sistema. Sono riservati agli sviluppatori di sistemi e alle teste di cazzo pazzo come me, che fanno le loro cose. Scrivo intestazioni di sistema, bootloader e kernel OS, quindi queste regole non fanno per me. Quel che è peggio che violare questa regola è usare le funzioni C standard come strcpy o asctime. – Timo

Problemi correlati