web-dev-qa-db-ja.com

C ++で列挙型を宣言するときにtypedefを使用するのはなぜですか?

私は何年もC++を書いたことはありませんが、今ではそれを取り戻そうとしています。それから私はこれに出くわし、あきらめることを考えました:

typedef enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

これは何ですか?ここでtypedefキーワードが使用されているのはなぜですか?名前TokenTypeがこの宣言に2回現れるのはなぜですか?セマンティクスはこれとどう違うのですか:

enum TokenType
{
    blah1 = 0x00000000,
    blah2=0x01000000,
    blah3=0x02000000
};
171
Tim Merrifield

Cでは、enumを最初の方法で宣言すると、次のように使用できます。

TokenType my_type;

2番目のスタイルを使用する場合、次のように変数を宣言する必要があります。

enum TokenType my_type;

他の人が述べたように、これはC++に違いをもたらしません。私の推測では、これを書いたのは中心的なCプログラマーか、CコードをC++としてコンパイルしているのでしょう。どちらにしても、コードの動作には影響しません。

147
Ryan Fox

あなたがそうするなら、それはCの遺産です。

enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
};

あなたは次のようなことをしてそれを使用する必要があります:

enum TokenType foo;

しかし、これを行う場合:

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

あなたは宣言することができます:

TokenType foo;

ただし、C++では、前の定義のみを使用して、Cのtypedefにあるかのように使用できます。

91
mat

あなたはそれをする必要はありません。 C(C++ではない)では、列挙型のデータ要素を参照するためにenum Enumnameを使用する必要がありました。単純化するために、単一の名前データ型にtypedefを許可しました。

typedef enum MyEnum { 
  //...
} MyEnum;

列挙型のパラメータをとる関数を次のように定義できます

void f( MyEnum x )

長いのではなく

void f( enum MyEnum x )

Typenameの名前は、enumの名前と同じである必要はないことに注意してください。構造体でも同じことが起こります。

一方、C++では、列挙型、クラス、および構造体に名前で型として直接アクセスできるため、必須ではありません。

// C++
enum MyEnum {
   // ...
};
void f( MyEnum x ); // Correct C++, Error in C

Cでは、型を列挙型以外の何かに変更できるため、良いスタイルです。

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

foo(enum e_TokenType token);  /* this can only be passed as an enum */

foo(TokenType token); /* TokenType can be defined to something else later
                         without changing this declaration */

C++では、C++またはCとしてコンパイルされるように列挙型を定義できます。

10
BeWarned

Cからのホールドオーバー.

6
Tim

Cには名前空間がないと言う人もいますが、それは技術的には正しくありません。次の3つがあります。

  1. タグ(enumunion、およびstruct
  2. ラベル
  3. (ほかのすべて)

typedef enum { } XYZ;は匿名列挙を宣言し、XYZという名前でグローバル名前空間にインポートします。

typedef enum ABC { } XYZ;は、タグ名前空間でABCという名前の列挙型を宣言し、XYZとしてグローバル名前空間にインポートします。

一部の人々は、すべてをtypedefするために別々の名前空間を気にしたくない。ネームスペースが必要なため、他の人はtypedefしません。

5
russbishop

これはちょっと古いですが、とにかく、私が今年初めに出会ったときに感謝していたように、私がタイプしようとしているリンクに感謝することを願っています。

ここで それは です。厄介なtypedefを把握しなければならないとき、私は常に頭にある説明を引用する必要があります。

変数宣言では、導入された名前は対応する型のインスタンスです。 [...]ただし、typedefキーワードが宣言の前にある場合、導入された名前は対応する型のエイリアスです

多くの人が以前に言ったように、C++で列挙型を宣言するtypedefを使用する必要はありません。しかし、それはtypedefの構文の説明です!私はそれが役立つことを願っています(おそらく10年近くなのでOPではないかもしれませんが、この種のことを理解するのに苦労している人は誰でも)。

3

「なぜ」の質問に対する実際の回答(この古い質問の上の既存の回答では驚くほど無視されます)は、このenum宣言はおそらく、両方のCおよびC++コード(つまり、CおよびC++の両方の実装ファイルに含まれます)。このようなヘッダーファイルを作成する技術は、両方の言語で適切な互換性のある言語機能を選択する作成者の能力に依存しています。

1
AnT

一部のCコードスタイルガイドでは、typedefバージョンは「明快さ」と「単純さ」に適していると言われています。 typedefは宣言されたオブジェクトの実際の性質を難読化するため、私は同意しません。実際、C変数を宣言するとき、オブジェクトが実際に何であるかを明確にしたいので、typedefを使用しません。この選択は、古いコードが実際に何をするかをより速く思い出すのに役立ち、将来コードを保守するときに他の人に役立ちます。

1
AdRiX