私はC++プログラミングの初心者です。
今日、私は新しいトピックに遭遇しました:強く型付けされたenum
。私はそれを少し研究しましたが、今まで私たちがなぜこれを必要とするのか、同じものの使用は何ですか?
たとえば、次の場合:
enum xyz{a, b, c};
/*a = 0, b = 1, c = 2, (Typical C format)*/
なぜ書く必要があるのか:
enum class xyz{a, b, c};
ここで何をしようとしていますか?私の最も重要な疑問は、それを使用する方法です。簡単な例を挙げていただければわかります。
OK、最初の例:古いスタイルの列挙型には独自のスコープがありません:
enum Animals {Bear, Cat, Chicken};
enum Birds {Eagle, Duck, Chicken}; // error! Chicken has already been declared!
enum class Fruits { Apple, Pear, Orange };
enum class Colours { Blue, White, Orange }; // no problem!
第二に、それらは暗黙的に整数型に変換するため、奇妙な動作を引き起こす可能性があります。
bool b = Bear && Duck; // what?
最後に、C++ 11列挙型の基本的な整数型を指定できます。
enum class Foo : char { A, B, C};
以前は、基盤となるタイプが指定されていなかったため、プラットフォーム間の互換性の問題が発生する可能性がありました。 編集コメントで指摘されているように、C++ 11の「古いスタイル」列挙の基になる整数型も指定できます。
このIBMページ に列挙に関する良い記事があります。非常に詳細でよく書かれています。ここにいくつかの重要なポイントがあります:
スコープ付き列挙型は、通常の列挙型が被るほとんどの制限を解決します。完全な型の安全性、明確に定義された基本型、スコープの問題、前方宣言です。
enum class
の値は、実際にはenum class
型であり、C-enumsの場合はunderlying_type
ではありません。
enum xyz { a, b, c};
enum class xyz_c { d, f, e };
void f(xyz x)
{
}
void f_c(xyz_c x)
{
}
// OK.
f(0);
// OK for C++03 and C++11.
f(a);
// OK with C++11.
f(xyz::a);
// ERROR.
f_c(0);
// OK.
f_c(xyz_c::d);
列挙クラス(「新しい列挙」、「強い列挙」)は、従来のC++列挙の3つの問題に対処します。
enums
は暗黙的にint
に変換され、列挙を整数として機能させたくない場合にエラーが発生します。enums
は、列挙子を周囲のスコープにエクスポートし、名前の衝突を引き起こします。enum
の基本型を指定できないため、混乱、互換性の問題が発生し、前方宣言ができなくなります。enum class
( "strong enums")は強く型付けされ、スコープが設定されています:
enum Alert { green, yellow, orange, red }; // traditional enum
enum class Color { red, blue }; // scoped and strongly typed enum
// no export of enumerator names into enclosing scope
// no implicit conversion to int
enum class TrafficLight { red, yellow, green };
Alert a = 7; // error (as ever in C++)
Color c = 7; // error: no int->Color conversion
int a2 = red; // ok: Alert->int conversion
int a3 = Alert::red; // error in C++98; ok in C++11
int a4 = blue; // error: blue not in scope
int a5 = Color::blue; // error: not Color->int conversion
Color a6 = Color::blue; // ok
示されているように、従来の列挙型は通常どおり機能しますが、オプションで列挙型の名前で修飾できます。
新しい列挙は、従来の列挙の側面(名前の値)をクラスの側面(スコープメンバーおよび変換の不在)と組み合わせているため、「列挙クラス」です。
基になる型を指定できると、相互運用性がより簡単になり、列挙のサイズが保証されます。
enum class Color : char { red, blue }; // compact representation
enum class TrafficLight { red, yellow, green }; // by default, the underlying type is int
enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U }; // how big is an E?
// (whatever the old rules say;
// i.e. "implementation defined")
enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U }; // now we can be specific
また、列挙型の前方宣言を有効にします。
enum class Color_code : char; // (forward) declaration
void foobar(Color_code* p); // use of forward declaration
// ...
enum class Color_code : char { red, yellow, green, blue }; // definition
基になる型は、符号付きまたは符号なし整数型のいずれかでなければなりません。デフォルトはint
です。
標準ライブラリでは、enum
クラスが次の目的で使用されます。
<system_error>
:enum class errc
;<memory>
:enum class pointer_safety { relaxed, preferred, strict };
<iosfwd>
:enum class io_errc { stream = 1 };
<future>
:enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };
これらのいくつかには、==
などの演算子が定義されています。
列挙スコープ
列挙は、列挙子を周囲のスコープにエクスポートします。これには2つの欠点があります。最初に、同じスコープで宣言された異なる列挙型の2つの列挙子が同じ名前を持っている場合、名前の競合が発生する可能性があります。第二に、列挙名を含む完全修飾名を持つ列挙子を使用することはできません。
enum ESet {a0, a, a1, b1, c3};
enum EAlpha{a, b, c}
select = ESet::a; // error
select = a; // is ambigious