Je suis un débutant en programmation C++.
Aujourd'hui, je tombe sur un nouveau sujet: fortement typé enum
. Je l'ai un peu étudié, mais jusqu'à présent, je suis incapable de savoir pourquoi avons-nous besoin de cela et à quoi sert-il?
Par exemple si nous avons:
enum xyz{a, b, c};
/*a = 0, b = 1, c = 2, (Typical C format)*/
Pourquoi avons-nous besoin d'écrire:
enum class xyz{a, b, c};
Qu'essayons-nous de faire ici? Mon doute le plus important est de savoir comment l'utiliser. Pourriez-vous donner un petit exemple, qui me fera comprendre.
OK, premier exemple: les enums de style ancien n'ont pas leur propre portée:
enum Animals {Bear, Cat, Chicken};
enum Birds {Eagle, Duck, Chicken}; // error! Chicken has already been declared!
enum class Fruits { Apple, Pear, Orange };
enum class Colours { Blue, White, Orange }; // no problem!
Deuxièmement, ils se convertissent implicitement en types intégraux, ce qui peut entraîner un comportement étrange:
bool b = Bear && Duck; // what?
Enfin, vous pouvez spécifier le type intégral sous-jacent des énumérations C++ 11:
enum class Foo : char { A, B, C};
Auparavant, le type sous-jacent n'était pas spécifié, ce qui pourrait entraîner des problèmes de compatibilité entre plates-formes. Edit Il a été souligné dans les commentaires que vous pouvez également spécifier le type intégral sous-jacent d'un enum "ancien style" en C++ 11.
Il y a un bon article sur les enums sur cette page IBM , il est très détaillé et bien écrit. Voici quelques points importants en un mot:
Les énumérations de portée résolvent la plupart des limitations imposées par les énumérations habituelles: sécurité du type complet, type sous-jacent bien défini, problèmes de portée et déclaration aval.
Valeurs de enum class
est vraiment de type enum class
, ne pas underlying_type
comme pour le C-enum.
enum xyz { a, b, c};
enum class xyz_c { d, f, e };
void f(xyz x)
{
}
void f_c(xyz_c x)
{
}
// OK.
f(0);
// OK for C++03 and C++11.
f(a);
// OK with C++11.
f(xyz::a);
// ERROR.
f_c(0);
// OK.
f_c(xyz_c::d);
Les classes enum ("new enums", "strong enums") résolvent trois problèmes avec les énumérations C++ traditionnelles:
enums
convertit implicitement en int
, provoquant des erreurs lorsque quelqu'un ne veut pas qu'une énumération agisse comme un entier.enums
exporte ses énumérateurs vers la portée environnante, ce qui provoque des conflits de noms.enum
ne peut pas être spécifié, ce qui entraîne une confusion, des problèmes de compatibilité et rend impossible la déclaration en aval.enum class
("strong enums") sont fortement typés et étendus:
enum Alert { green, yellow, orange, red }; // traditional enum
enum class Color { red, blue }; // scoped and strongly typed enum
// no export of enumerator names into enclosing scope
// no implicit conversion to int
enum class TrafficLight { red, yellow, green };
Alert a = 7; // error (as ever in C++)
Color c = 7; // error: no int->Color conversion
int a2 = red; // ok: Alert->int conversion
int a3 = Alert::red; // error in C++98; ok in C++11
int a4 = blue; // error: blue not in scope
int a5 = Color::blue; // error: not Color->int conversion
Color a6 = Color::blue; // ok
Comme indiqué, les enums traditionnels fonctionnent comme d'habitude, mais vous pouvez maintenant éventuellement vous qualifier avec le nom de l'énum.
Les nouveaux enum sont "enum class" car ils combinent des aspects des énumérations traditionnelles (valeurs de noms) avec des aspects des classes (membres définis et absence de conversions).
Etre capable de spécifier le type sous-jacent permet une interopérabilité plus simple et des tailles d'énumérations garanties:
enum class Color : char { red, blue }; // compact representation
enum class TrafficLight { red, yellow, green }; // by default, the underlying type is int
enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U }; // how big is an E?
// (whatever the old rules say;
// i.e. "implementation defined")
enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U }; // now we can be specific
Il permet également la déclaration en aval des énumérations:
enum class Color_code : char; // (forward) declaration
void foobar(Color_code* p); // use of forward declaration
// ...
enum class Color_code : char { red, yellow, green, blue }; // definition
Le type sous-jacent doit être l'un des types entiers signés ou non signés; la valeur par défaut est int
.
Dans la bibliothèque standard, les classes enum
sont utilisées pour:
<system_error>
: enum class errc
;<memory>
: enum class pointer_safety { relaxed, preferred, strict };
<iosfwd>
: enum class io_errc { stream = 1 };
<future>
: enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };
Plusieurs d’entre eux ont des opérateurs, tels que ==
défini.
Enum Scope
Les énumérations exportent leurs énumérateurs vers la portée environnante. Cela a deux inconvénients. Premièrement, cela peut conduire à des conflits de noms, si deux énumérateurs de différentes énumérations déclarées dans la même étendue ont le même nom; deuxièmement, il n'est pas possible d'utiliser un énumérateur avec un nom complet, y compris le nom enum.
enum ESet {a0, a, a1, b1, c3};
enum EAlpha{a, b, c}
select = ESet::a; // error
select = a; // is ambigious