2009-05-12 17 views
27

私はC++標準を少し読んで、enumの動作を理解しようとしてきました。実際に私が考えていたよりも多くのことがあります。C++でのC++列挙型の基本的な型0x

スコープ付きの列挙では、enum-base句で指定されていない限り、基底型がintであることは明らかです(これは整数型でもかまいません)。スコープを持たない列挙型の

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

は、動作しますし、それがあることが必要である場合を除き、それは、int型よりも大きくならないことを任意の整数タイプにすることができ、基礎となるタイプのように思えます。

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

、スコープ外enumarationsの基になる型が標準化されていないので、1のシリアライズインスタンスに対処する最良の方法は何ですか?今のところ私は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; 
} 
+2

列挙型クラスがあるだけでC++ 0xの... – Klaim

+2

+1、この質問は-1edた理由がわからない... –

+1

おそらく質問者は明らかに、既存および提案された標準化文書を区別することはできませんので? –

答えて

5

私は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 
+1

enumの演算子<<を書くことに感謝します。私は自分自身のことを考えていたはずです。 – criddell

+0

あなたのコメントでは、演算子<<を書くことに言及しました。上記のコードは、その過負荷で正しく動作することを理解しています。しかし、<<がオーバーロードされていない場合は、シリアル化する前にcをintにキャストしてください。 – criddell

+0

いいえ私はint型にキャストしませんでした。それを行った後、enum演算子を追加した後に、enumを書き出してキャストを削除するコード内のすべての場所を見つける必要があるからです。 – markh44

16

列挙型クラスそれはC++ 03には存在しないが、C++0x機能です。

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

例を使用して表現される:

は(私は元の質問の一部ではなかったと思う)シリアライズ部分については
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. 

、私がに好みますenumアイテムは、コードの振る舞いを変更せずに並べ替えることができる(そして時には並べ替える)ので、通常は名前が表す整数値よりも安定しているので、列挙型アイテムを文字列に相当する(そして戻す)ヘルパークラスを作成します。

1

enum class colorについて:このC++/CLI(C++ .NET)または将来のC++ 0xコードですか?

シリアル化の場合、コピーするバイト数を知るために、sizeof(color)で列挙型のサイズを取得できます。

14

私は古いものがとても面倒だったので、新しい回答を作成することにしました。

std::underlying_type_t<E> 

と関心のため、オーバーロードの解決のアイデア:とにかく、ちょうどあなたがこのいずれかを使用して列挙の基になる型を取得することができますについてのC++ 11何かを、言いたいです。しかし、@lotharが提案したように、名前を使用して列挙を保存してください。

オーバーロードの原因は、列挙型からint型、unsigned int型、long型、unsigned long型の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 

シリアライズデータのサイズが一定の幅ではないので、それは(この連載の問題に特に関心がありません、これは時に問題を引き起こす可能性があります列挙型とその基になる型が変更されています)、列挙型全体を格納する型を見つけることは一般的に面白いです。乾杯!

+0

'std :: underlying_type'は、正しい型を得るための最良の解決策です。ちょっとした修正:ヘルパー** 'std :: underlying_type_t ' **は** C++ 14 **で利用できます。 ** C++ 11 **では、代わりに** 'std :: underlying_type :: type' **を使用する必要があります。 – ollo

5
#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; 
+2

実際には、コードブロックを逆流させるのではなく、実際に何かが何をしているのかを説明するのが通例です。 –

+0

私は説明に刺すつもりです。このコードでは、基本的な型の列挙型を理解するためにコンパイラにテンプレートマジックを使用しています。私は、シリアライゼーションの目的のために基になる型を理解する方法を尋ねてきました。 – criddell