web-dev-qa-db-ja.com

列挙型にリストされていない値を含めることはできますか?

たとえば、

enum E
{
  Foo = 0,
  Bar = 1
};

今、私たちは

enum E v = ( enum E ) 2;

その後

switch ( v )
{
  case Foo:
    doFoo();
  break;
  case Bar:
    doBar();
  break;
  default:
    // Is the compiler required to honor this?
    doOther();
  break;
}

上記のスイッチは列挙型の可能なすべてのリストされた値を処理するので、コンパイラーが上記のdefaultブランチを最適化することを許可されますか、それ以外の場合は列挙型の値がリスト?

CとC++の動作は似ているはずですが、問題は両方の言語についてです。ただし、その場合にCとC++に違いがある場合は、それについても知っておくと便利です。

36
dragonroot

C++の状況

C++では、各列挙型には基礎となる整数型があります。明示的に指定されている場合、fixedにすることができます(例:enum test2 : long { a,b};)またはscoped列挙型の場合のデフォルトでintである場合(例:enum class test { a,b };):

[dcl.enum]/5:各列挙型は、他のすべてのタイプとは異なるタイプを定義します。各列挙には、基礎となるタイプもあります。 (...)明示的に指定されていない場合、スコープ付き列挙型の基になる型はintです。これらの場合、基になる型は修正されたと言います。

unscoped列挙型の場合、基になる型は明示的に修正されていません(あなたの例)、標準はコンパイラに柔軟性を与えます:

[dcl.enum]/7:基になる型が固定されていない列挙の場合、基になる型は、すべての列挙子の値を表すことができる整数型です。列挙で定義されます。 (...)列挙型の値がintまたはunsigned intに収まらない場合を除いて、基になる型がintより大きくならないことを除いて、基になる型として使用される整数型は実装定義です。

さて、非常にトリッキーなこと:enum変数が保持できる値は、基になる型がかどうかによって異なります修繕

  • 固定されている場合、 "列挙型の値は基になる型の値です。"

  • 一方、最小の列挙子と最大の列挙子を保持できるのは、最小ビットフィールドの最小値と最大値内の整数値です。

コードはほとんどのコンパイラで機能しますが、2番目のケースになりますが、最も小さいビットフィールドのサイズは1であるため、すべての準拠C++コンパイラで確実に保持できる唯一の値は0と1の間です...

結論:値を2に設定できるようにしたい場合は、列挙型をスコープ付き列挙型にするか、基礎となるものを明示的に示す必要がありますタイプ。**

もっと読む:

Cの状況

Cの状況ははるかに単純です(C11):

6.2.5/16:列挙は、名前付き整数定数値のセットで構成されます。それぞれの列挙型は、異なる列挙型を構成します。

つまり、基本的にはintです。

6.7.2.2./2列挙定数の値を定義する式は、intとして表現可能な値を持つ整数定数式でなければなりません。

次の制限があります。

各列挙型は、char、符号付き整数型、または符号なし整数型と互換性があります。タイプの選択は実装定義ですが、列挙型のすべてのメンバーの値を表すことができます。

23
Christophe

Cでは、enum型は、すべてのenum定数を保持するのに十分な大きさの整数型です。

(C11、6.7.2.2p4)「各列挙型は、char、符号付き整数型、または符号なし整数型と互換性があります。型の選択は実装定義です110)が、すべての値を表すことができます。列挙のメンバー」。

enum Eの選択されたタイプが_Boolであるとしましょう。 _Boolオブジェクトは、値0および1のみを格納できます。未定義の動作を呼び出さずに、_Boolオブジェクトに0または1とは異なる値を格納することはできません。

その場合、コンパイラーは、enum Eタイプのオブジェクトは、厳密に準拠するプログラムで0または1のみを保持できると想定して、defaultスイッチケース。

3
ouah

また、7.2/10:

算術型または列挙型の式は、列挙型に明示的に変換できます。列挙型の列挙値の範囲内にある場合、値は変更されません。それ以外の場合、結果の列挙値は指定されていません。

0
Paul

C++ Std 7.2.7 [dcl.enum]:

どの列挙子によっても定義されていない値を持つ列挙を定義することが可能です。

したがって、列挙子リストにリストされていない列挙値を持つことができます。

しかし、特定のケースでは、「基礎となるタイプ」は「固定」されていません(7.2.5)。その場合、仕様ではどちらが基になるタイプであるかについては述べられていませんが、整数である必要があります。 charはそのような最小の型であるため、列挙子リストで指定されていない列挙型の他の値があると結論付けることができます。

ところで、vに割り当てられた他の値がないと判断できる場合、コンパイラーはケースを最適化できると思います。これは安全ですが、まだそれほどスマートなコンパイラーはないと思います。

0
Kevin C