C'est une question très intéressante. La réponse est simple, c'est littéralement indéfini: la norme ne dit rien à propos de cette affaire.
Pour avoir un meilleur exemple, prenons cette enum
:
enum foo : bool { True=true, undefined };
Selon la norme:
[dcl.enum]/2: [...] Un agent recenseur, définition sans un initialiseur donne à l' agent recenseur à la valeur obtenue par l'augmentation de la valeur de la précédente agent recenseur par un.
Par conséquent, la valeur de foo::undefined
dans notre exemple, est - 2
(true+1
). Qui ne peut pas être représenté comme un bool
.
Est-il mal formé?
Non, selon la norme, il est parfaitement valide, seule la non-correction d'un type sous-jacent ont une restriction de ne pas être en mesure de représenter l'ensemble de l'énumérateur valeurs:
[dcl.enum]/7: Pour une énumération dont le type sous-jacent n'est pas fixe, [...] Si aucun type intégral peut représenter toutes les énumérateur des valeurs de l'énumération est mal formé.
Il ne dit rien sur un fixe sous-jacent type qui ne peut pas représenter tous les énumérateur de valeurs.
Quelle est la valeur de l'original de la question de l' oops
et undefined
?
Il est pas défini: la norme ne dit rien à propos de cette affaire.
Les valeurs possibles pour foo::undefined
:
- Plus haute valeur possible (
true
): undefined
et oops
devrait être de type sous-jacent'valeur maximale.
- La plus faible valeur possible (
false
): le type sous-jacent'valeur minimale. Remarque: En nombres entiers signés, il ne serait pas conforme au comportement actuel de dépassement d'Entier (comportement indéfini).
- Valeur aléatoire (?): le compilateur de choisir une valeur.
Le problème avec l'ensemble de ces valeurs, c'est qu'il peut résulter de deux champs avec la même valeur (par exemple, foo::True == foo::undefined
).
La différence entre l'initialiseur (par exemple, undefined=2
) et "implicite" de l'initialiseur (par exemple, True=true, undefined
)
Selon la norme:
[dcl.enum]/5: Si le sous-jacent est de type fixe, le type de chaque agent recenseur avant l'accolade fermante est le type sous-jacent et de la constante de l'expression de l' agent recenseur, la définition doit être converti expression constante du type sous-jacent.
En d'autres termes:
enum bar : bool { undefined=2 };
est équivalent à
enum bar : bool { undefined=static_cast<bool>(2) };
Et puis, bar::undefined
sera true
. Dans "implicite" de l'initialiseur, il ne serait pas le cas: ce paragraphe standard de dire ça à propos de seulement initialiseur, et pas sur "implicite" de l'initialiseur.
Résumé
- Avec cette façon, il est possible pour un
enum
avec un fixe sous-jacents de type à avoir irreprésentable valeurs.
- Leur valeur n'est pas définie par la norme.
Selon la question et les commentaires, ce n'est pas valable dans GCC et clang mais valable pour MSVS-2015 (avec un avertissement).