2009-05-22 8 views
31

Pourquoi les gens utilisent-ils les enums en C++ comme constantes lorsqu'ils peuvent utiliser const?Pourquoi les gens utilisent-ils les enums en C++ comme constantes alors qu'ils peuvent utiliser const?

+0

je sais que ce est un très vieux fil, mais pourriez-vous donner un exemple? Quand j'ai lu cette question, je pensais à la ligne de code qui renvoie un int à partir d'une fonction, mais utilise une énumération pour définir des 'versions' spécifiques de la valeur de retour, par ex. À mon avis, il est faux d'utiliser une énumération de cette façon, à moins que, comme on le dit, votre compilateur soit limité dans sa fonctionnalité par rapport à la constante statique. – cosimo193

+0

Copie possible de [Devrais-je utiliser #define, enum ou const?] (Https://stackoverflow.com/questions/112433/should-i-use-define-enum-or-const) –

Répondre

20

Une énumération implique un ensemble de constantes associées, de sorte que les informations supplémentaires sur la relation doivent être utiles dans leur modèle du problème en question.

+30

Hm, ça n'a pas l'air comme une réponse à la question (même si elle a été acceptée). Les gens utilisent des énumérations où ils pourraient utiliser 'const' et les valeurs ne sont pas liées. Souvent, vous verrez 'enum {QUELQUE CHOSE = 2232; } '(comme ça, énumération sans nom avec une seule valeur) au lieu de' const int SOMETHING = 2232; '.C'est parce que enum n'obtient jamais de stockage alors que la variable const est toujours une variable et obtiendra un stockage (statique) si le compilateur ne peut pas en prouver le besoin, ce qu'il ne peut souvent pas faire. –

+0

Une autre raison est que les variables POD "const" sont une nouvelle fonctionnalité C++, et beaucoup de bases de code plus anciennes (et les programmeurs qui préfèrent la compatibilité plus élevée) existent toujours. –

-1

Une raison est que const nécessite plus taper:

enum { Val1, Val2, Val3 }; 

... contre ...

const int Val1=0, Val2=1, Val3=2; 
+1

Ce n'est pas la seule raison. En outre, il n'y a pas de grande différence dans la frappe. –

34

énumérations sont des types distincts, de sorte que vous pouvez faire des choses type orienté comme la surcharge avec les:

enum Color { Red,Green,Blue }; 
enum Size { Big,Little }; 

void f(Color c) { 
} 

void f(Size s) { 
} 

int main() { 
    f(Red); 
    f(Big); 
} 
+5

Ce n'est pas ce que la question posée. La question est: pourquoi les gens écrivent des choses comme: enum {Margin = 50}; – Claudio

20

Il y a une raison historique aussi lorsqu'il s'agit de modèle rencontré aprogramming. Certains compilateurs peuvent utiliser des valeurs d'une énumération, mais pas un const int statique pour instancier une classe.

template <int N> 
struct foo 
{ 
    enum { Value = foo<N-1>::Value + N }; 
}; 

template <> 
struct foo<0> 
{ 
    enum { Value = 0; } 
}; 

Maintenant, vous pouvez le faire de la façon plus sensible:

template <int N> 
struct foo 
{ 
    static const int Value = foo<N-1>::Value + N; 
}; 

template <> 
struct foo<0> 
{ 
    static const int Value = 0; 
}; 

Une autre raison possible est qu'un int const statique peut avoir la mémoire qui lui est réservé lors de l'exécution, alors qu'une ENUM ne va jamais avoir un emplacement mémoire réel qui lui est réservé, et sera traité au moment de la compilation. Voir this related question.

10

Les énumérations sont plus descriptives lorsqu'elles sont utilisées. Considérez:

int f(int fg, int bg) 

contre

int f(COLOR fg, COLOR bg) 

En outre, les énumérations donnent un peu plus-sécurité de type, parce que

  • entiers ne sont pas convertibles en ENUM implicitement les types
  • ENUM d'un le type n'est pas implicitement convertible en enum d'un autre type
+0

Il s'agit d'un ancien thread, mais les deux instructions à la fin de cette réponse sont fausses et doivent être corrigées. – motiz88

+4

"les entiers ne sont pas implicitement convertibles en types enum" et "enum d'un type n'est pas implicitement convertible en enum d'un autre type" - false. Les 'enum's simples convertiront silencieusement vers/à partir des entiers, en C++ comme en C. Donc ils ne fournissent strictement cette sécurité. Cependant, en C++ 11, il y a 'enum class' qui est un" re-imagining "propre à C++ dans' enum': Les conversions implicites ont disparu, et en plus les noms de valeur doivent toujours être qualifiés. Ceci est similaire à C# 'enum's, et évite les problèmes de collision de nom/pollution de l'espace de nom qui surviennent avec l'ancien' enum' de C. – motiz88

+0

@ motiz88 - Je pense que vous pouvez être confus sur celui-ci. Essayez ce code sur gcc (vous devrez le reformater vous-même): int main() {enum MyEnum1 {VAL11, VAL12, VAL13}; enum MyEnum2 {VAL21, VAL22, VAL23, VAL24}; int int1 = VAL11; MyEnum1 enum1 = 3; MyEnum2 enum2 = VAL11; enum2 = enum1; int int2 = enum1; renvoie 0; } Les valeurs enum convertissent implicitement en entiers, mais pas l'inverse, et les "types enum" ne sont pas convertis implicitement entre eux. En principe, je crois que ASk est correct ici, mais je ne pense pas que ce soit une réponse à la question de l'op! – cosimo193

4

Enums peut également être utilisé comme nom de type. Vous pouvez donc définir une fonction qui prend enum en paramètre, ce qui rend plus clair quels types de valeurs devraient être donnés comme arguments à la fonction, comparé à avoir les valeurs définies comme variables const et la fonction n'acceptant que "int" comme argument.

Tenir compte:

enum my_new_fangled_type { 
    baz = 0, 
    meh = 1 
}; 

void foo (my_new_fangled_type bar) // bar can be a value listed in the enum 
{ 
    ... 
} 

contre:

int const baz = 0; 
int const meh = 1; 

void foo (int bar) // what are valid values for bar? 
{ 
    ... 
} 
+1

'typedef int my_new_fangled_type; void foo (barre my_new_fangled_type); 'Problème résolu, aucune énumération nécessaire, et je peux changer la représentation de la mémoire en remplaçant' typedef int' par 'typedef uchar' ou quelque chose de ce genre. :) – weberc2

0

L'utilisation d'un ENUM documente les choix valides d'une manière laconique et permet au compilateur de les appliquer.

Si elles utilisent des constantes globales enum store, comme Pi, par exemple, je ne sais pas quel est leur but.

+1

enum est un type intégral, je ne crois pas qu'il peut stocker une constante telle que Pi sans perte de précision significative :) – ASk

+0

ils pourraient stocker 314159 et juste div de 10^5 à chaque fois: P espérons que l'exemple donne la bonne idée de ce que je voulais dire par constantes globales, cependant. – dss539

10

J'aime le comportement automatique qui peut être utilisé avec les énumérations, par exemple:

enum {NONE, START, HEY, HO, LAST}; 

Ensuite, il est facile à boucle jusqu'à LAST, et quand un nouvel état (ou tout ce qui est représenté) est ajouté, la la logique s'adapte.

for (int i = NONE; i < LAST; i++) 
{ 
    // Do stuff... 
} 

Ajouter quelque chose ...

enum {NONE, START, HEY, WEE, HO, LAST}; 

La boucle s'adapte ...

+0

A moins que quelqu'un ajoute accidentellement le nouveau littéral enum à la fin de la liste, ou décide de donner des valeurs non contiguës aux littéraux (par exemple enum {} NONE = 0, START = 4, HEY = 7 etc ....). – cosimo193

5

Avant les fournisseurs de compilateur mis en œuvre la norme ISO/CEI 14882: 1998 C++ standard, ce code pour définir une constante une étendue de classe a abouti à une erreur de compilation:

class Foo { 
    static const int MAX_LEN = 80; 
    ... 
}; 

Si la constante est un type entier, un travail de contour est nécessaire. éfinir dans un ENUM intérieur de la classe:

class Foo { 
    enum { 
     MAX_LEN = 80 
    }; 
    ... 
}; 
+0

Les constantes non statiques ne peuvent pas être initialisées de cette manière. Je crois que vous vouliez dire "static const int Val1". Il existe également des inconvénients dans l'utilisation de cette méthode d'initialisation en classe: il n'est pas garanti que le symbole de Val1 soit créé. – ASk

+0

@ASk: Le problème est que le symbole "static const int Val1" n'est pas garanti de ne pas ** être ** généré, donc le programmeur utilise enum à la place, car cela ne crée pas de symbole du tout. –

41

Bruce Eckel donne une raison en Thinking in C++:

In older versions of C++, static const was not supported inside classes. This meant that const was useless for constant expressions inside classes. However, people still wanted to do this so a typical solution (usually referred to as the “enum hack”) was to use an untagged enum with no instances. An enumeration must have all its values established at compile time, it’s local to the class, and its values are available for constant expressions. Thus, you will commonly see:

#include <iostream> 
using namespace std; 

class Bunch { 
    enum { size = 1000 }; 
    int i[size]; 
}; 

int main() { 
    cout << "sizeof(Bunch) = " << sizeof(Bunch) 
     << ", sizeof(i[1000]) = " 
     << sizeof(int[1000]) << endl; 
} 

[Modifier]

Je pense qu'il serait plus juste de relier le site de Bruce Eckel : .

2

Certains débogueurs afficheront le nom de l'énumération au lieu de sa valeur lors du débogage. Cela peut être très utile. Je sais que je préfère voir day_of_week = MONDAY que day_of_week = 1.

2

Il est en partie parce que les compilateurs anciens ne prennent pas en charge la déclaration d'une véritable constante de classe

class C 
{ 
    const int ARealConstant = 10; 
}; 

Nous avons donc dû faire

class C 
{ 
    enum { ARealConstant = 10 }; 
}; 

Pour cette raison, de nombreuses bibliothèques portables continuer à utiliser ce formulaire .

L'autre raison est que les énumérations peuvent être utilisés comme un dispositif syntaxique pratique pour organiser des constantes de classe dans ceux qui sont liés, et ceux qui ne sont pas

class DirectorySearcher 
{ 
    enum options 
    { 
    showFiles = 0x01, 
    showDirectories = 0x02, 
    showLinks = 0x04, 
    }; 
}; 

vs

class Integer 
{ 
    enum { treatAsNumeric = true }; 
    enum { treatAsIntegral = true }; 
    enum { treatAsString = false }; 
}; 
Questions connexes