les espaces de noms pour les types enum - les meilleures pratiques
Souvent, on a besoin de plusieurs types énumérés ensemble. Parfois, on a un conflit de nom. Deux solutions à cela viennent à l'esprit: utiliser un espace de noms, ou de l'utilisation de 'plus grand' enum les noms d'éléments. Encore, l'espace de solution a deux implémentations possibles: un mannequin de classe avec imbriqué enum, ou une pleine soufflé espace de noms.
Je suis à la recherche pour les avantages et inconvénients des trois approches.
Exemple:
//oft seen hand-crafted name clash solution
enum eColors { cRed, cColorBlue, cGreen, cYellow, cColorsEnd };
enum eFeelings { cAngry, cFeelingBlue, cHappy, cFeelingsEnd };
void setPenColor( const eColors c ) {
switch (c) {
default: assert(false);
break; case cRed: //...
break; case cColorBlue: //...
//...
}
}
//(ab)using a class as a namespace
class Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; };
class Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; };
void setPenColor( const Colors::e c ) {
switch (c) {
default: assert(false);
break; case Colors::cRed: //...
break; case Colors::cBlue: //...
//...
}
}
//a real namespace?
namespace Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; };
namespace Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; };
void setPenColor( const Colors::e c ) {
switch (c) {
default: assert(false);
break; case Colors::cRed: //...
break; case Colors::cBlue: //...
//...
}
}
- Tout d'abord, je voudrais utiliser Couleur::Rouge, Sentiment:la Colère, etc
- bonne question, j'ai utilisé la méthode d'espace de noms.... 😉
- le "c" préfixe sur tout ce qui blesse la lisibilité.
- pourquoi, je vous remercie pour l'ouverture du hongrois discussion 🙂
- Notez que vous n'avez pas besoin de nom de l'énumération que dans
enum e {...}
, les énumérations peuvent être anonymes, c'est à direenum {...}
, qui fait beaucoup plus de sens quand enveloppé dans l'espace de noms ou de classe. - si vous avez un non-nommées enum, quel est son type? par exemple: enum TOTO{}; void bar(FOO e); mais si nous avons enum{} void bar2(???);
- Vous avez raison, mais seulement pour les classes. Pour les espaces de noms, il est préférable de retenir les énumérations non-anonyme, parce que vous ne pouvez pas utiliser l'espace de noms du nom lui-même comme un type nom; vous pouvez utiliser uniquement le nom de l'intérieure enum pour que.
Vous devez vous connecter pour publier un commentaire.
C++03 répondre à:
La bénéficier à partir d'un
namespace
(plus d'unclass
), c'est que vous pouvez utiliserusing
déclarations quand vous le voulez.La problème avec l'aide d'un
namespace
est que les espaces de noms peut être développé ailleurs dans le code. Dans un projet d'envergure, vous ne serait pas garanti que deux énumérations ne sont pas les deux pensent qu'ils sont appeléseFeelings
De plus simple-à la recherche de code, j'utilise un
struct
, comme vous l'avez sans doute voulez que le contenu soit publique.Si vous faites l'une de ces pratiques, vous êtes en avance de la courbe et n'est probablement pas nécessaire d'examiner de manière plus poussée.
Plus récente, C++11 conseils:
Si vous êtes à l'aide de C++11 ou une version ultérieure,
enum class
sera implicitement la portée de l'enum valeurs dans l'énumération du nom.Avec
enum class
vous perdrez des conversions implicites et des comparaisons types d'entiers, mais dans la pratique qui peut vous aider à découvrir ambigu ou code bogué.FYI Dans C++0x il y a une nouvelle syntaxe pour les cas comme ce que vous avez mentionné (voir C++0x page wiki)
J'ai hybridé les réponses précédentes à quelque chose comme ceci: (EDIT: Ceci n'est utile que pour les pré - C++11. Si vous êtes à l'aide de C++11, utiliser
enum class
)J'ai un gros fichier d'en-tête qui contient tous mes projet enums, parce que ces énumérations sont partagés entre les travailleurs des classes et il n'est pas judicieux de mettre les énumérations dans le travailleur classes elles-mêmes.
La
struct
évite le public: sucre syntaxique, et latypedef
vous permet en fait de déclarer des variables de ces énumérations dans les autres travailleurs des classes.Je ne pense pas que l'aide d'un espace de noms permet à tous les. C'est peut-être parce que je suis un programmeur C#, et il vous ont d'utiliser le type enum nom lorsque l'on se réfère aux valeurs, donc je suis habitué à elle.
...
Je voudrais absolument éviter d'utiliser une classe pour cela, utiliser un espace de noms à la place. La question se résume à savoir si l'utilisation d'un espace de noms ou d'utiliser des identifiants uniques pour les énumérations. Personnellement, je préfère utiliser un espace de noms, de sorte que mes identifiants peuvent être plus courtes et espérons-le, plus à l'auto-explicatif. Ensuite, le code de l'application peut utiliser un "using namespace" directive et de rendre le tout plus lisible.
À partir de votre exemple ci-dessus:
Colors someColor = Red;
, parce que l'espace de noms ne constitue pas un type. Vous devez écrireColors::e someColor = Red;
au lieu de cela, ce qui est assez contre-intuitif.Colors::e someColor
même avec unstruct/class
si vous voulais l'utiliser dans unswitch
déclaration? Si vous utilisez un anonymeenum
ensuite le commutateur ne serait pas en mesure d'évaluer unstruct
.const e c
semble difficilement lisible pour moi 🙂 Ne pas le faire. À l'aide d'un espace de noms, cependant, est très bien.Une différence entre l'utilisation d'une classe ou d'un espace de noms est que la classe ne peut pas être rouverte comme un espace de noms peut. Cela permet d'éviter la possibilité que l'espace de noms peuvent être utilisées dans le futur, mais il y a aussi le problème que vous ne pouvez pas ajouter à l'ensemble des énumérations soit.
Un avantage pour l'utilisation d'une classe, c'est qu'ils peuvent être utilisés en tant que modèle type des arguments, ce qui n'est pas le cas pour les espaces de noms:
Personnellement, je ne suis pas un fan de à l'aide de, et je préfère les noms entièrement qualifiés, donc je ne vois pas vraiment ça comme un plus pour les espaces de noms. Cependant, ce n'est probablement pas la décision la plus importante que vous ferez dans votre projet!
Avantage de l'utilisation d'une classe, c'est que vous pouvez construire une classe à part entière sur le dessus de cela.
Comme l'exemple ci-dessus montre, à l'aide d'une classe, vous pouvez:
Il suffit de noter que vous devez déclarer
operator enum_type()
de sorte que C++ voudrais savoir comment convertir votre classe en sous-jacentes enum. Sinon, vous ne serez pas en mesure de passer le type deswitch
déclaration.Depuis les énumérations sont limitées à leur cadre englobant, il est probablement préférable de les envelopper dans quelque chose pour éviter de polluer l'espace de noms global et pour aider à éviter les collisions de noms. Je préfère un espace de noms de la classe tout simplement parce que
namespace
se sent comme un sac de contenance, tandis queclass
se sent comme un robuste objet (cf. lestruct
vsclass
débat). Un avantage possible à un espace de noms est qu'il peut être étendu par la suite - utile si vous avez à traiter avec de la troisième partie du code que vous ne pouvez pas modifier.C'est tout à fait discutable bien sûr, quand nous arrivons à énumérer les classes C++0x.
J'ai aussi tendance à emballer mes énumérations dans les classes.
Comme signalé par Richard Corden, au profit d'une classe, c'est que c'est un type au sens du c++ et de sorte que vous pouvez l'utiliser avec les modèles.
J'ai spéciale boîte à outils::Enum class pour mes besoins que je me spécialise pour tous les modèles qui offre des fonctions de base (principalement: cartographie d'une valeur d'énumération à un std::string, de sorte que les e/S sont plus facile à lire).
Mon petit modèle a aussi l'avantage de vraiment vérifier pour les valeurs autorisées. Le compilateur est une sorte de preuve de laxisme en matière de vérifier si la valeur de l'enum:
Il m'a toujours agacé que le compilateur ne sera pas attraper cette, puisque vous êtes de gauche avec une valeur d'enum qui n'a pas de sens (et que vous ne vous attendez pas).
De la même façon:
Une fois de plus principale sera de retour une erreur.
Le problème est que le compilateur de s'adapter à la enum dans la plus petite représentation (ici nous avons besoin de 2 bits) et que tout ce qui s'inscrit dans cette représentation, qui est considéré comme une valeur valide.
Il y a aussi le problème que parfois vous préférez avoir une boucle sur les valeurs possibles au lieu d'un interrupteur, de sorte que vous n'avez pas à modifier tous vous change chaque fois que vous ajoutez une valeur de l'enum.
Dans l'ensemble mon little helper vraiment facilité les choses pour mes énumérations (bien sûr, il ajoute des frais généraux) et il est seulement possible parce que j'ai nid chaque enum dans sa propre structure 🙂