111 votes

espaces de noms pour les types d'enum - meilleures pratiques

Souvent, on a besoin de plusieurs types énumérés ensemble. Parfois, il y a un conflit de noms. Deux solutions à ce problème viennent à l'esprit : utiliser un espace de noms, ou utiliser des noms d'éléments d'énumération "plus grands". Cependant, la solution de l'espace de noms a deux implémentations possibles : une classe fictive avec des énumérations imbriquées ou un espace de noms à part entière.

Je cherche les avantages et les inconvénients de ces 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: //...
        //...
    }
  }

19 votes

Tout d'abord, j'utiliserais Color::Red, Feeling:Angry, etc.

0 votes

Bonne question, j'ai utilisé la méthode de l'espace de nom.... ;)

19 votes

Le préfixe "c" sur tout nuit à la lisibilité.

83voto

Drew Dormann Points 25025

Réponse originale de C++03 :

El avantage d'un namespace (sur un class ) est que vous pouvez utiliser using quand vous le souhaitez.

El problème avec l'utilisation d'un namespace est que les espaces de noms peuvent être étendus ailleurs dans le code. Dans un grand projet, vous ne pouvez pas être sûr que deux enums distincts ne pensent pas tous les deux s'appeler eFeelings

Pour un code plus simple, j'utilise un struct car vous souhaitez sans doute que le contenu soit public.

Si vous suivez l'une de ces pratiques, vous êtes en avance sur votre temps et vous n'avez probablement pas besoin de vous pencher davantage sur la question.

Conseil plus récent, C++11 :

Si vous utilisez C++11 ou une version ultérieure, enum class mettra implicitement les valeurs de l'enum dans le nom de l'enum.

Avec enum class vous perdrez les conversions et comparaisons implicites avec les types entiers, mais en pratique, cela peut vous aider à découvrir du code ambigu ou bogué.

4 votes

Je suis d'accord avec l'idée de la structure. Et merci pour le compliment :)

3 votes

+1 Je ne me souvenais plus de la syntaxe "classe enum" du C++11. Sans cette fonctionnalité, les enums sont incomplets.

0 votes

Est-il possible d'utiliser "using" pour la portée implicite de la "classe d'énumération" ? Par exemple, si l'on ajoute "using Color::e ;" à un code, pourra-t-on utiliser "cRed" et savoir que cela devrait être Color::e::cRed ?

22voto

jmihalicza Points 1382

FYI Dans C++0x il y a une nouvelle syntaxe pour les cas comme celui que vous avez mentionné (voir Page wiki C++0x )

enum class eColors { ... };
enum class eFeelings { ... };

10voto

Charles Anderson Points 3837

J'éviterais définitivement d'utiliser une classe pour cela ; utilisez plutôt un espace de noms. La question se résume à savoir s'il faut utiliser un espace de noms ou des identifiants uniques pour les valeurs de l'enum. Personnellement, j'utiliserais un espace de noms pour que mes identifiants soient plus courts et, je l'espère, plus explicites. Le code de l'application pourrait alors utiliser une directive "using namespace" et rendre le tout plus lisible.

D'après votre exemple ci-dessus :

using namespace Colors;

void setPenColor( const e c ) {
    switch (c) {
        default: assert(false);
        break; case cRed: //...
        break; case cBlue: //...
        //...
    }
}

0 votes

Pourriez-vous donner un indice sur pourquoi vous préférez un espace de nom à une classe ?

0 votes

@xtofl : vous ne pouvez pas écrire "using class Colors`".

2 votes

@MSalters : Tu ne peux pas non plus écrire Colors someColor = Red; car l'espace de noms ne constitue pas un type. Il faudrait écrire Colors::e someColor = Red; à la place, ce qui est assez contre-intuitif.

7voto

Richard Corden Points 12292

Une différence entre l'utilisation d'une classe et d'un espace de nom est que la classe ne peut pas être rouverte comme le peut un espace de nom. Cela évite la possibilité d'abuser de l'espace de noms à l'avenir, mais il y a aussi le problème que vous ne pouvez pas non plus ajouter à l'ensemble des énumérations.

Un avantage possible de l'utilisation d'une classe est qu'elle peut être utilisée comme argument de type de modèle, ce qui n'est pas le cas pour les espaces de noms :

class Colors {
public:
  enum TYPE {
    Red,
    Green,
    Blue
  };
};

template <typename T> void foo (T t) {
  typedef typename T::TYPE EnumType;
  // ...
}

Personnellement, je ne suis pas un fan de en utilisant et je préfère les noms pleinement qualifiés, donc je ne vois pas vraiment cela comme un avantage pour les espaces de noms. Cependant, ce n'est probablement pas la décision la plus importante que vous prendrez dans votre projet !

0 votes

La non-réouverture des classes est également un inconvénient potentiel. La liste des couleurs n'est pas finie non plus.

1 votes

Je pense que le fait de ne pas repocher une classe est un avantage potentiel. Si je veux plus de couleurs, je recompile simplement la classe avec plus de couleurs. Si je ne peux pas faire cela (disons que je n'ai pas le code), alors je ne veux pas y toucher de toute façon.

0 votes

@MSalters : L'absence de possibilité de réouverture d'une classe n'est non seulement pas un inconvénient, mais aussi un outil de sécurité. Parce que lorsqu'il est possible de rouvrir une classe et d'ajouter des valeurs à l'enum, cela peut casser le code d'autres bibliothèques qui dépendent déjà de cet enum et ne connaissent que l'ancien ensemble de valeurs. Il accepterait alors volontiers ces nouvelles valeurs, mais se casserait à l'exécution parce qu'il ne saurait pas quoi en faire. N'oubliez pas le principe "ouvert-fermé" : Une classe doit être fermée pour modification de mais ouvert à extension de . Par extension, j'entends qu'il ne s'agit pas d'ajouter au code existant, mais de le recouvrir avec le nouveau code (par exemple, la dérivation).

5voto

Michael Kristofik Points 16035

Étant donné que les enums ont une portée limitée à la portée qui les englobe, il est probablement préférable de les envelopper dans un fichier quelque chose pour éviter de polluer l'espace de nom global et pour éviter les collisions de noms. Je préfère un espace de noms à une classe simplement parce que namespace ressemble à un sac de rétention, alors que class ressemble à un objet robuste (cf. struct vs. class débat). Un avantage possible d'un espace de noms est qu'il peut être étendu ultérieurement - utile si vous avez affaire à du code tiers que vous ne pouvez pas modifier.

Tout cela est bien sûr discutable lorsque nous aurons des classes enum avec C++0x.

0 votes

Les classes d'énumération... il faut que je me renseigne !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X