web-dev-qa-db-ja.com

C ++ 0xのC ++列挙型の基になる型

私は列挙型がどのように機能するかを理解するためにC++標準を少し読んでみました。実際、私が当初思っていた以上のものがあります。

スコープ付き列挙型の場合、enum-base句で特に指定されていない限り、基になる型がintであることは明らかです(任意の整数型にすることができます)。

enum class color { red, green, blue};  // these are int

スコープ外の列挙型の場合、基になる型は機能する任意の整数型であり、必要がない限り、intより大きくなることはないようです。

enum color { red, green, blue};  // underlying type may vary

スコープ外の列挙型の基になるタイプは標準化されていないため、インスタンスのシリアル化を処理する最良の方法は何ですか?これまで、書き込み時にintに変換してから、intにシリアル化し、読み取り時にスイッチにenum変数を設定してきましたが、少し不格好なようです。もっと良い方法はありますか?

enum color { red, green, blue };
color c = red;
// to serialize
archive << (int)c;
// to deserialize
int i;
archive >> i;
switch(i) {
  case 0: c = red; break;
  case 1: c = green; break;
  case 2: c = blue; break;
}
27
criddell

私はC++ 0xのものを読んだことがないので、コメントできませんでした。

シリアル化に関しては、列挙型を読み戻すときにスイッチは必要ありません。列挙型にキャストするだけです。

ただし、ストリームに書き込むときはキャストしません。これは、列挙型に演算子<<を記述して、書き込まれている不正な値をキャッチできるようにするか、代わりに文字列を書き出すことを決定できるためです。

enum color { red, green, blue };
color c = red;

// to serialize
archive << c;    // Removed cast

// to deserialize
int i;
archive >> i;
c = (color)i;    // Removed switch
5
markh44

enum classC++ 0x 機能であり、C++ 03には存在しません。

標準のC++では、列挙型はタイプセーフではありません。列挙型が異なる場合でも、これらは事実上整数です。これにより、異なる列挙型の2つの列挙値を比較できます。 C++ 03が提供する唯一の安全性は、ある列挙型の整数または値が暗黙的に別の列挙型に変換されないことです。さらに、基になる整数型である整数のサイズを明示的に指定することはできません。それは実装定義です。最後に、列挙値はそれを囲むスコープにスコープされます。したがって、2つの別々の列挙が一致するメンバー名を持つことはできません。 C++ 0xでは、これらの問題のない列挙の特別な分類が可能になります。これは、列挙型クラス宣言を使用して表現されます

例(ウィキペディアの記事から):

enum Enum1;                   //Illegal in C++ and C++0x; no size is explicitly specified.
enum Enum2 : unsigned int;    //Legal in C++0x.
enum class Enum3;             //Legal in C++0x, because enum class declarations have a default type of "int".
enum class Enum4: unsigned int; //Legal C++0x.
enum Enum2 : unsigned short;  //Illegal in C++0x, because Enum2 was previously declared with a different type.

シリアル化の部分(元の質問の一部ではなかったと思います)については、名前が通常整数値よりも安定しているため、列挙型アイテムを同等の文字列に(およびその逆に)変換するヘルパークラスを作成することを好みます列挙型アイテムは、コードの動作を変更せずに並べ替えることができます(場合によっては並べ替えることができます)。

16
lothar

私の古いものがとても散らかっていたので、私は新しい答えを作成することにしました。とにかく、C++ 11について何か言いたいのですが、これを使用して、基になる型の列挙型を取得できます。

std::underlying_type_t<E>

そして興味のために、過負荷解決のアイデア。ただし、@ lotharによって提案されているように、名前を使用して列挙を格納してください。

過負荷の解決は、列挙型から、基になる型のすべての値を表すことができるint、unsigned int、long、unsignedlongの最初の昇格への1つの昇格が存在するという事実から生じます。他の整数型への変換はランクが低く、過負荷の解決はそれを好みません。

char (& f(int) )[1];
char (& f(unsigned int) )[2];

char (& f(long) )[3];
char (& f(unsigned long) )[4];

char const* names[] = { 
    "int", "unsigned int", 
    "long", "unsigned long"
};

enum a { A = INT_MIN };
enum b { B = UINT_MAX };
enum c { C = LONG_MIN };
enum d { D = ULONG_MAX };

template<typename T> void print_underlying() {
    std::cout << names[sizeof(f(T()))-1] << std::endl;
}

int main() { 
    print_underlying<a>();
    print_underlying<b>();
    print_underlying<c>();
    print_underlying<d>();
}

そして、これをここに印刷します:

int
unsigned int
int
unsigned int

このシリアル化の問題には特に関心がありません(シリアル化されるデータのサイズが一定の幅ではないため、列挙とその基になる型が変更されると問題が発生する可能性があります)が、一般に、格納する型を理解することは興味深いことです。列挙全体。乾杯!

#include <type_traits>

enum a { bla1, bla2 };
typedef typename std::underlying_type<a>::type underlying_type;

if (std::is_same<underlying_type, int>::value)
  std::cout << "It's an int!" << endl;
else if (std::is_same<underlying_type, unsigned int>::value)
  std::cout << "It's an uint!" << endl;
5
jaroslav Šmíd

_enum class color_について:これはC++/CLI(C++ .NET)ですか、それとも将来のC++ 0xコードですか?

シリアル化の場合、sizeof(color)を使用して列挙型のサイズを取得し、コピーするバイト数を知ることができます。

1
Dario