[解決済み] enumクラスに無効な値をstatic_castしたらどうなる?
質問
このC++のコードを考えてみましょう。
enum class Color : char { red = 0x1, yellow = 0x2 }
// ...
char *data = ReadFile();
Color color = static_cast<Color>(data[0]);
data[0]が実際には100であったとします。規格上、colorは何色に設定されているのでしょうか? 特に、もし私が後で
switch (color) {
// ... red and yellow cases omitted
default:
// handle error
break;
}
は、標準ではデフォルトがヒットすることを保証しているのでしょうか?もしそうでなければ、ここでエラーをチェックするための適切で、最も効率的で、最もエレガントな方法は何でしょうか?標準はこれについての保証をしますが、プレーンなenumではどうでしょうか?
どのように解決するのですか?
<ブロッククオート標準ではどのような色に設定されていますか?
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
である必要があります。
expr]/4と比較
式の評価中に、結果が数学的に定義されていない、またはその型に対して表現可能な値の範囲にない場合、動作は未定義となります。
CWG1766以前では、変換積分型 -> 列挙型では 不特定値 . という質問があります。 不特定値はその型に対して表現可能な値の外にあることができますか? 私は、答えは いいえ -- もし、その答えが はい であった場合、符号付きの型に対する操作で得られる保証には、"この操作は未定義の値を生成する" と "この操作は未定義の動作をする" の間に何の違いもないでしょう。
したがって、CWG 1766 より前は、たとえ
static_cast<Color>(10000)
は
ではない
はUBを呼び出します。しかし、CWG1766以降では
する。
はUBを呼び出す。
さて、この
switch
ステートメントを使用します。
[stmt.switch]・2
条件は、積分型、列挙型、またはクラス型でなければならない。[...] 積分型の昇格が行われる。
[conv.prom]/4
<ブロッククオートのプルバリューは 非スコープの のprvalueは、その基礎となる型のprvalueに変換することができます(7.2)。さらに、もし積分促進がその基礎となる型に適用できるなら、基礎となる型が固定されている非スコープの列挙型のprvalueも、促進された基礎となる型のprvalueに変換することができる。
注意: スコープされた enum の基本型は
enum-base
は
int
. スコープされていない列挙型の場合、基礎となる型は実装で定義されますが、以下の値より大きくてはいけません。
int
もし
int
は全ての列挙子の値を含むことができます。
には 非スコープの列挙 の場合、これは /1 につながります。
以外の整数型のprvalは
bool
,char16_t
,char32_t
またはwchar_t
のランクより小さく、整数変換のランク (4.13) はint
の型のprvalueに変換することができます。int
もしint
はソース型の全ての値を表すことができ、そうでなければ、ソース型のprvalueは、タイプunsigned int
.
の場合は
非スコープの
の列挙の場合、私たちが扱うのは
int
を扱うことになります。の場合
スコープ
の列挙(
enum class
と
enum struct
を含む)、積分促進は適用されません。いずれにせよ、積分促進はUBにもつながりません。格納された値は、基礎となる型の範囲内と
int
.
[stmt.switch]/5件
<ブロッククオート
を実行すると
switch
ステートメントが実行されると、その条件が評価され、各ケース定数と比較されます。ケース定数のいずれかが条件の値と等しい場合、制御はマッチした
case
ラベルに続くステートメントに制御が移る。もし
case
定数が条件にマッチせず、かつ
default
ラベルがある場合、制御は
default
ラベルで指定されたステートメントに制御が移ります。
は
default
のラベルがヒットするはずです。
注意: 比較演算子をもう一度見てみることもできますが、参照される "comparison" では明示的に使用されていません。実際、私たちのケースでは、スコープされた、またはスコープされていない列挙型の UB を導入するヒントがありません。
おまけですが、これに関してもenumでプレーンなものは規格で保証されているのでしょうか?
の有無は
enum
がスコープされているかどうかは、ここでは何の違いも生じません。しかし、基礎となる型が固定されているかどうかの違いはあります。完全な[decl.enum]/7は。
基礎となる型が固定されている列挙型については、列挙型の値は基礎となる型の値である。そうでない場合、列挙型に対して e min は最小の列挙体であり e が最大 が最大であれば、列挙された値は範囲内の b min から b <サブ 最大 は,次のように定義される.ここで
K
である1
は 2 の補数表現で0
は 1 の補数または符号-倍数表現になります。 b 最大 と同等以上の最小の値です。 max(|e min | -K
, |e <サブ 最大 |) と等しく、かつ 2 M - 1 ここでM
は非負の整数である。 b min が0であれば e min は非負であり -(b 最大 +K
) のように、それ以外の場合は
次の列挙を見てみましょう。
enum ColorUnfixed /* no fixed underlying type */
{
red = 0x1,
yellow = 0x2
}
すべてのスコープ付き列挙型は固定した基礎型を持つので、これをスコープ付き列挙型として定義することはできないことに注意してください。
幸いなことに
ColorUnfixed
の最小の列挙子は
red = 0x1
であり、したがって
max(|e
min
| -
K
, |e
<サブ
最大
|)
は
|e
最大
|
というのは、いずれにしても
yellow = 0x2
. より大きいか等しい最小の値は
2
と等しく、かつ
2
M
- 1
正の整数の場合
M
は
3
(
2
2
- 1
). (1ビット単位で範囲を広げることを意図していると思われます。) よって、以下のようになります。
b
最大
は
3
であり
bmin
は
0
.
したがって
100
の範囲外になってしまいます。
ColorUnfixed
の範囲外であり
static_cast
は、CWG 1766以前は未指定の値を生成し、CWG 1766以降は未定義の動作を生成するでしょう。
関連
-
[解決済み】「std::operator」で「operator<<」にマッチするものがない。
-
[解決済み] スタックアロケーションにより初期化されていない値が作成された
-
[解決済み] C++でクラスと構造体はいつ使い分けるべきか?
-
[解決済み] ベースクラスのコンストラクタを呼び出す際のルールは?
-
[解決済み] C++のstructとclassの違いは何ですか?
-
[解決済み] コピーエリジョンと戻り値の最適化とは何ですか?
-
[解決済み] C++で、仮想基底クラスとは何ですか?
-
[解決済み】static_cast<>とC言語のキャストの違いは何ですか?
-
[解決済み】C++のenumクラスはメソッドを持つことができますか?
-
[解決済み】なぜenumクラスはプレーンなenumより好ましいのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】LLVMで暗黙のうちに削除されたコピーコンストラクタの呼び出し
-
[解決済み】クラステンプレートの引数リストがない
-
[解決済み】C++でユーザー入力を待つ【重複あり
-
[解決済み] error: 'if' の前に unqualified-id を期待した。
-
[解決済み】fpermissiveフラグは何をするのですか?
-
[解決済み】エラー:不完全な型へのメンバーアクセス:前方宣言の
-
[解決済み】浮動小数点数の乱数生成
-
[解決済み】C++ - 適切なデフォルトコンストラクタがない [重複]。
-
[解決済み] 数値定数の前にunqualified-idを付けて、数値を定義することを期待する。
-
[解決済み] 警告:暗黙の定数変換でのオーバーフロー