Was ist die Farbe gemäß dem Standard eingestellt?
Antwort mit einem Zitat aus den Standards C ++ 11 und C ++ 14:
[expr.static.cast] / 10
Ein Wert vom Integral- oder Aufzählungstyp kann explizit in einen Aufzählungstyp konvertiert werden. Der Wert bleibt unverändert, wenn der ursprüngliche Wert im Bereich der Aufzählungswerte (7.2) liegt. Andernfalls ist der resultierende Wert nicht angegeben (und liegt möglicherweise nicht in diesem Bereich).
Schauen wir uns den Bereich der Aufzählungswerte an : [dcl.enum] / 7
Bei einer Aufzählung, deren zugrunde liegender Typ festgelegt ist, sind die Werte der Aufzählung die Werte des zugrunde liegenden Typs.
Vor CWG 1766 (C ++ 11, C ++ 14)
Daher wird für angegeben data[0] == 100
, dass der resultierende Wert angegeben wird (*) und kein undefiniertes Verhalten (UB) beteiligt ist. Im Allgemeinen kann beim Umwandeln vom zugrunde liegenden Typ in den Aufzählungstyp kein Wert in data[0]
zu UB für die führen static_cast
.
Nach CWG 1766 (C ++ 17)
Siehe CWG-Defekt 1766 . Der Absatz [expr.static.cast] p10 wurde verstärkt, sodass Sie jetzt UB aufrufen können , wenn Sie einen Wert, der außerhalb des darstellbaren Bereichs einer Aufzählung liegt, in den Aufzählungstyp umwandeln. Dies gilt immer noch nicht für das Szenario in der Frage, da data[0]
es sich um den zugrunde liegenden Typ der Aufzählung handelt (siehe oben).
Bitte beachten Sie, dass CWG 1766 als Fehler im Standard angesehen wird. Daher wird davon ausgegangen, dass Compiler-Implementierer auf ihre C ++ 11- und C ++ 14-Kompilierungsmodi anwenden.
(*) char
muss mindestens 8 Bit breit sein, muss es aber nicht sein unsigned
. Der maximal speicherbare Wert muss mindestens 127
Anhang E der Norm C99 entsprechen.
Vergleiche mit [Ausdruck] / 4
Wenn während der Auswertung eines Ausdrucks das Ergebnis nicht mathematisch definiert ist oder nicht im Bereich der darstellbaren Werte für seinen Typ liegt, ist das Verhalten undefiniert.
Vor CWG 1766 kann der Konvertierungsintegraltyp -> Aufzählungstyp einen nicht angegebenen Wert erzeugen . Die Frage ist: Kann ein nicht spezifizierter Wert außerhalb der darstellbaren Werte für seinen Typ liegen? Ich glaube, die Antwort ist nein - wenn die Antwort ja wäre , gäbe es keinen Unterschied in den Garantien, die Sie für Operationen mit vorzeichenbehafteten Typen erhalten, zwischen "diese Operation erzeugt einen nicht spezifizierten Wert" und "diese Operation hat ein undefiniertes Verhalten".
Daher vor der CWG 1766, auch static_cast<Color>(10000)
würde nicht invoke UB; aber nach CWG 1766 ruft es UB auf.
Nun die switch
Aussage:
[stmt.switch] / 2
Die Bedingung muss vom Integraltyp, Aufzählungstyp oder Klassentyp sein. [...] Integrale Werbeaktionen werden durchgeführt.
[conv.prom] / 4
Ein Wert eines nicht skalierten Aufzählungstyps, dessen zugrunde liegender Typ fest ist (7.2), kann in einen Wert seines zugrunde liegenden Typs konvertiert werden. Wenn eine integrale Heraufstufung auf den zugrunde liegenden Typ angewendet werden kann, kann außerdem ein Wert eines nicht skalierten Aufzählungstyps, dessen zugrunde liegender Typ festgelegt ist, in einen Wert des heraufgestuften zugrunde liegenden Typs konvertiert werden.
Hinweis: Der zugrunde liegende Typ einer Enum mit Gültigkeitsbereich ohne Enum-Base ist int
. Für Aufzählungen ohne Gültigkeitsbereich ist der zugrunde liegende Typ implementierungsdefiniert, darf jedoch nicht größer sein, als int
wenn int
die Werte aller Aufzähler enthalten können.
Für eine Aufzählung ohne Gültigkeitsbereich führt uns dies zu / 1
A prvalue eines ganzzahligen anderen Typ als bool
, char16_t
, char32_t
, oder wchar_t
deren ganzzahlige Umwandlungs rank (4,13) geringer ist als der Rang der int
auf ein prvalue vom Typ umgewandelt werden , int
wenn int
alle Werte des Quelltyps darstellen; Andernfalls kann der Quellwert in einen Wert vom Typ konvertiert werden unsigned int
.
Im Falle einer Aufzählung ohne Gültigkeitsbereich würden wir uns hier mit int
s befassen . Für Aufzählungen mit Gültigkeitsbereich ( enum class
und enum struct
) gilt keine integrale Werbung. In keiner Weise führt die integrale Heraufstufung auch nicht zu UB, da der gespeicherte Wert im Bereich des zugrunde liegenden Typs und im Bereich von liegt int
.
[stmt.switch] / 5
Wenn die switch
Anweisung ausgeführt wird, wird ihre Bedingung ausgewertet und mit jeder Fallkonstante verglichen. Wenn eine der Fallkonstanten dem Wert der Bedingung entspricht, wird die Steuerung an die Anweisung übergeben, die auf die übereinstimmende case
Bezeichnung folgt . Wenn keine case
Konstante mit der Bedingung übereinstimmt und eine default
Beschriftung vorhanden ist , wird die Steuerung an die durch die default
Beschriftung gekennzeichnete Anweisung übergeben .
Das default
Etikett sollte getroffen werden.
Hinweis: Man könnte sich den Vergleichsoperator noch einmal ansehen, er wird jedoch im genannten "Vergleich" nicht explizit verwendet. Tatsächlich gibt es in unserem Fall keinen Hinweis darauf, dass UB für Enumes mit oder ohne Gültigkeitsbereich eingeführt werden würde.
Gibt der Standard als Bonus diesbezüglich Garantien, jedoch mit einfacher Aufzählung?
Ob das enum
Geltungsbereich ist oder nicht, spielt hier keine Rolle. Es macht jedoch einen Unterschied, ob der zugrunde liegende Typ festgelegt ist oder nicht. Das vollständige [dec.enum] / 7 lautet:
Bei einer Aufzählung, deren zugrunde liegender Typ festgelegt ist, sind die Werte der Aufzählung die Werte des zugrunde liegenden Typs. Ansonsten für eine Aufzählung , wo e min ist die kleinste enumerator und e max die größte ist, sind die Werte der Enumeration die Werte im Bereich b min bis b max , wie folgt definiert: Es sei K
sein 1
Komplement - Darstellung für eine Zweier-und 0
für eine das eigene Komplement oder die Darstellung der Vorzeichengröße. b max ist der kleinste Wert größer oder gleich max (| e min | - K
, | e max |) und gleich 2M - 1 , wobeiM
eine nicht negative ganze Zahl ist. b min ist Null, wenn e min nicht negativ ist und - (b max + K
) sonst.
Schauen wir uns die folgende Aufzählung an:
enum ColorUnfixed /* no fixed underlying type */
{
red = 0x1,
yellow = 0x2
}
Beachten Sie, dass wir dies nicht als Aufzählung mit Gültigkeitsbereich definieren können, da alle Aufzählungen mit Gültigkeitsbereich feste zugrunde liegende Typen haben.
Glücklicherweise ist ColorUnfixed
der kleinste Enumerator red = 0x1
, also ist max (| e min | - K
, | e max |) gleich | e max | auf jeden Fall, das ist yellow = 0x2
. Der kleinste Wert größer oder gleich 2
, der für eine positive ganze Zahl gleich 2 M - 1M
ist, ist 3
( 2 2 - 1 ). (Ich denke, die Absicht ist es, den Bereich in 1-Bit-Schritten erweitern zu lassen.) Daraus folgt, dass b max ist 3
und bmin ist 0
.
Daher 100
würde außerhalb des Bereichs von liegen ColorUnfixed
und static_cast
würde einen nicht spezifizierten Wert vor CWG 1766 und ein undefiniertes Verhalten nach CWG 1766 erzeugen.
char
, also "Der Wert bleibt unverändert, wenn der ursprüngliche Wert im Bereich der Aufzählungswerte (7.2) liegt." gilt.