Jusqu'ici, on a surtout manipulé des nombres et des strings. Pour modéliser le monde réel, on peut vouloir un nombre limité de valeurs qu'une variable peut prendre. Tu peux avoir besoin d'un type dédié, avec quelques valeurs distinctes portant des noms distincts. Par exemple, dans une usine de skateboards, le matériau du plateau ne pourrait être choisi que parmi l'érable, le bambou ou le plastique.
Tu pourrais encoder ces valeurs avec des entiers, mais il te faudrait du code supplémentaire pour vérifier qu'une valeur invalide ne remonte pas du système pour ce matériau.
La signification de ces nombres magiques est difficile à retracer dans le code source, et ils prêtent facilement à confusion.
Les enumerations servent à écrire un code plus expressif et à limiter les erreurs de comparaison involontaires.
Le terme précis pour ce type d'énumération est scoped enumeration.
L'extrait ci-dessous montre comment écrire une enumeration DeckMaterial.
Remarque le mot-clé enum class et le ; à la fin de la définition :
enum class DeckMaterial {
maple,
bamboo,
plastic
};
Maintenant, regarde une fonction de tarification dans la boutique de skate et remarque l'opérateur de résolution de portée (::) qui désigne un enumerator de l'enumeration :
double deck_price(double base_price, DeckMaterial material) {
if(material == DeckMaterial::plastic) {
return base_price * 0.9;
}
return base_price * 1.3;
}
Imagine que tu aies une seconde enumeration pour le matériau des roues :
enum class WheelMaterial {
steel,
clay,
plastic
};
Bien que les roues et le plateau puissent tous deux être en plastic, les deux ne peuvent pas être confondus.
Ce sont deux types différents : le plastic de DeckMaterial et le plastic de WheelMaterial.
Chaque enumeration a ses enumerators dans sa propre portée, son propre namespace.
C'est pour cette raison qu'on les appelle scoped enumerations.
Tu penses peut-être qu'avec un nom comme scoped, il doit aussi exister des énumérations unscoped, et tu as raison.
Les Unscoped enumerations sont de moins en moins populaires, car elles partagent toutes le même espace de noms global.
À cause de ce partage, on ne peut pas avoir deux unscoped enumerations avec les mêmes enumerators, comme plastic dans l'exemple ci-dessus.
De plus, les unscoped enumerations se convertissent implicitement en entiers.
Regarde l'exemple ci-dessous, qui donne un résultat surprenant :
enum CitrusFruits {
lemons, // 0
oranges, //1
};
enum IceCream {
walnut, // 0
apples, // 1
};
bool comparison{apples == oranges};
// => true
// Example from above:
bool comparison{DeckMaterial::plastic == WheelMaterial::plastic};
// => Does not compile!
Si tu veux convertir des scoped enumerations en entiers, tu peux utiliser static_cast<int>.