規格に基づいて設定されている色は何ですか?
C ++ 11およびC ++ 14標準からの引用で回答:
[expr.static.cast] / 10
整数型または列挙型の値は、明示的に列挙型に変換できます。元の値が列挙値の範囲(7.2)内にある場合、値は変更されません。それ以外の場合、結果の値は指定されていません(その範囲にはない場合があります)。
列挙値の範囲を調べてみましょう:[dcl.enum] / 7
基になる型が固定されている列挙型の場合、列挙の値は、基になる型の値です。
CWG 1766(C ++ 11、C ++ 14)より前のバージョンでは
、のためdata[0] == 100
に、結果の値が指定され(*)、未定義の動作(UB)は関係しません。より一般的には、基になる型から列挙型にキャストするときに、の値がのdata[0]
UBにつながることはありませんstatic_cast
。
CWG 1766以降(C ++ 17)CWG障害1766を
参照してください。[expr.static.cast] p10段落が強化されたため、列挙型の表現可能な範囲外の値を列挙型にキャストすると、UB を呼び出すことができるようになりました。これは問題のシナリオにはまだ当てはまりません。これdata[0]
は、列挙型の基礎となるタイプであるためです(上記参照)。
CWG 1766は規格の欠陥と見なされているため、コンパイラの実装者がC ++ 11およびC ++ 14コンパイルモードに適用することは認められています。
(*)char
は少なくとも8ビット幅である必要がありunsigned
ますが、である必要はありません。保存可能な最大値は、少なくとも127
C99標準のAnnex Eに準拠する必要があります。
[expr] / 4と比較
式の評価中に結果が数学的に定義されていないか、その型の表現可能な値の範囲にない場合、動作は未定義です。
CWG 1766より前のバージョンでは、変換整数型->列挙型は未指定の値を生成する可能性がありました。問題は、指定されていない値がその型の表現可能な値の外にある可能性があるかどうかです。私は答えはノーだと思います-答えがイエスだった場合、「このオペレーションは不特定の値を生成する」と「このオペレーションは未定義の動作をする」との間で、署名された型のオペレーションに対して得られる保証に違いはありません。
したがって、CWG 1766の前にもstatic_cast<Color>(10000)
希望しない UB呼び出します。しかし、CWG 1766以降は、UBを呼び出します。
さて、switch
ステートメント:
[標準スイッチ] / 2
条件は、整数型、列挙型、またはクラス型でなければなりません。[...] 統合プロモーションが実行されます。
[conv.prom] / 4
prvalue スコープ外の基底型固定されている列挙型(7.2)は、その基礎となるタイプのprvalueに変換することができます。さらに、基になる型に整数の昇格を適用できる場合は、基になる型が固定されているスコープのない列挙型のprvalueも、昇格した基になる型のprvalueに変換できます。
注:enum-baseのないスコープ付き列挙型の基になる型はint
です。スコープのない列挙型の場合、基になる型は実装定義ですが、すべての列挙子の値を含めることができるint
場合よりも大きくなることはありませんint
。
対象範囲外の列挙の場合、これは/ 1に導きます
以外の整数型のprvalue bool
、char16_t
、char32_t
、またはwchar_t
その整数変換ランク(4.13)未満のランクよりもint
タイプのprvalueに変換することができるint
場合はint
、ソース・タイプのすべての値を表すことができます。それ以外の場合は、ソースのprvalueをtypeのprvalueに変換できますunsigned int
。
対象範囲外の列挙の場合、int
ここではs を扱います。以下のためにスコープの列挙(enum class
およびenum struct
)、一切の積分プロモーションが適用されません。いずれにせよ、格納された値が基になる型の範囲との範囲であるため、整数の昇格はUBにもつながりませんint
。
[標準スイッチ] / 5
場合switch
ステートメントが実行され、その状態を評価し、それぞれの場合の定数と比較されます。ケース定数の1つが条件の値と等しい場合、制御は一致したcase
ラベルに続くステートメントに渡されます。case
条件に一致する定数がなく、default
ラベルがある場合、制御はラベルでラベル付けされたステートメントに渡されdefault
ます。
default
ラベルがヒットしなければなりません。
注:比較演算子をもう一度見ることもできますが、参照される「比較」では明示的に使用されていません。実際、私たちの場合、スコープ付きまたはスコープなしの列挙型にUBを導入するヒントはありません。
おまけとして、標準はこれについて何らかの保証をしていますが、明白な列挙型がありますか?
enum
スコープが設定されているかどうかにかかわらず、ここでは違いはありません。ただし、基になる型が固定されているかどうかにかかわらず、違いはあります。完全な[decl.enum] / 7は次のとおりです。
基になる型が固定されている列挙型の場合、列挙の値は、基になる型の値です。ここで、それ以外の場合は、列挙のためのE minは最小の列挙であり、E maxは最大であり、列挙の値は、範囲内の値であるBの分までBの最大値以下のように定義される:させるK
ことが1
2の補数表現および0
Aの1の補数または符号の大きさの表現。B maxはより最小値の大きいまたは等しい最大値(| Eの分 | - K
、| Eの最大値 |)とに等しい2M − 1。ここで、M
は負でない整数です。e minが負でない場合、 b minはゼロで、それ以外の場合は -(b max + )です。K
次の列挙を見てみましょう:
enum ColorUnfixed /* no fixed underlying type */
{
red = 0x1,
yellow = 0x2
}
すべてのスコープ付き列挙型には固定された基本型があるため、これをスコープ付き列挙型として定義できないことに注意してください。
幸い、ColorUnfixed
の最小の列挙子はred = 0x1
なので、max(| e min | − K
、| e max |)は| e max |に等しくなります。いずれにせよ、それはyellow = 0x2
です。最小値より大きい又は等しい2
と等しい、2 M - 1の正の整数のためには、M
である3
(2 2 - 1)。(私は意図は1ビットのステップで程度の範囲を可能にすることであると思う。)それは次のB maxがある3
とBminとがあります0
。
したがって、100
の範囲外ColorUnfixed
となり、static_cast
CWG 1766以前は不特定の値が生成され、CWG 1766以降は未定義の動作になります。
char
ので、「元の値が列挙値の範囲(7.2)内にある場合、値は変更されません。」適用されます。