2009-09-04 7 views
11

関数内で使用する整数定数を定義する典型的な方法は次のとおりC++コードで単一の定数を定義するためにenumを使用する理由はありますか?

const int NumbeOfElements = 10; 

クラス内で使用するための同じ:

class Class { 
... 
    static const int NumberOfElements = 10; 
}; 

次いでこれを固定サイズのアレイとして使用することができますこれはコンパイル時に知られていることを意味します。

昔のコンパイラは、後者の構文をサポートしていませんでしたし、列挙型を使用した理由です:

enum NumberOfElementsEnum { NumberOfElements = 10; } 

const int関数でと、クラスstatic const int構文の両方サポートするほとんどすべての広く使われているコンパイラでありますこの目的のためにenumを使用する何らかの理由がありますか?

答えて

23

理由は主に簡潔です。まず第一に、enumは匿名になります

class foo { 
    enum { bar = 1 }; 
}; 

これが効果的に積分定数としてbar紹介しています。上記はstatic const intより短いことに注意してください。

また、enumのメンバーなら、誰も&barと書くことはできません。あなたはこれを行う場合:

class foo { 
    static const int bar = 1; 
} 

、その後、あなたのクラスのクライアントは、この行います

printf("%p", &foo::bar); 

それから彼は(foo::barが定義されていないことをコンパイル時リンカエラーを取得します、なぜなら良く、など左辺値、そうではありません)。現実には、スタンダードが現在立っているので、barが使用され、積分定数式がでない場合は、(すなわち、そのような式が必要な場所は、enumイニシャライザ、caseラベル、型の配列サイズ(new[]を除く)、および整数型のテンプレート引数です。したがって、技術的に他の場所でbarを使用すると、定義が必要です。詳細については、C++ Core Language Active Issue 712を参照してください - まだ提案されている解決策はありません。

実際には、最近のほとんどのコンパイラはこれに慣れており、定義を必要とせずにstatic const intの変数のほとんどの "常識"の使用を取り除くことができます。しかしコーナーケースは異なるかもしれませんが、多くの人が匿名のenumを使う方が良いと考えています。そのためにはすべてが明瞭であり、まったく曖昧さはありません。

+1

うん、gccは-pedantic -Wall -Wextraを使ってもこれについて文句を言わない。とにかくリンク時までエラーを検出することはできないので、この種の移植性のないコードを診断しようとするのはあきらめるだけです –

+0

良い答え。あなたが明示的に言及していないもう一つの素晴らしいことは、列挙型はrvalueであり、ストレージはこれまで割り当てられていないということです。テンプレートのメタプログラミングや多数のクラステンプレートのインスタンス化を行っている場合、コンパイラの最適化に頼るのではなく、確実に*を知っている方がいいかもしれません。 – jalf

+1

クラスの外側に '静的const int 'の定義がない場合、そのために割り当てられた記憶域はありません。また、右辺値には記憶域を割り当てることができます(たとえば、一時変数は右辺値ですが、記憶域を使用します)。 –

-2

bottom line - use const。

詳細:

は、私はC++専門家ではないんだけど、これは、より一般的な設計の問題です。

必須ではなく、列挙型が1つ以上の値を持つ確率が非常に低い/存在しないと思われる場合は、通常のconstを使用します。 あなたが間違っていて、将来、ある時点でより多くの値が存在するとしても、enumを正しい選択にする - 単純なリファクタリングとconstをenumに変更する。

+0

これは、高水準設計の観点からは、 'enum'と' const'とではありません。これは、すべてのコンストラクトに関連するC++の欠点に関するものです。明白な答えはここで間違っています。 –

3

enumは暗黙のうちに整数に変換されていてもenumには独自の型があるので、実際にはenumを使用する理由はなく、実際にはstatic const intを使用する方が良いと思います。

+0

私は気にしていませんが、理由を教えてくれてうれしいです。ありがとう。 –

+3

列挙型に独自の型があるのはなぜですか?あなたのプログラムはあなたが超過することが許されていないタイプの割り当てを持っていますか? –

+0

@Rob Kennedyと同意します。強力な型の定数はenumの**ポイント**です。 –

9

静的定数を直接クラス定義に定義するのは、C++の後の追加です。多くの人がそれにはenumを使用する古い回避策に固執しています。クラス定義で直接定義された静的定数をサポートしていない古いコンパイラがまだ使用されていることさえあります。

+2

コンパイラの中には静的なconst intをインライン化するものではありませんが、enumは常にAFAIKにインライン化されるものがあります。 –

5

あなたの場合、私も定数を使用します。ただし、その他の関連する定数を追加する場合は、となる場合もあります。このように:そのような場合には

const int TextFile = 1; // XXX Maybe add other constants for binary files etc.? 

、私はこのような単一の値、とすぐに列挙型を使用します。

enum FileType { 
    TextFile = 1 
    // XXX Maybe add other values for binary files etc.? 
} 

理由は、私が使用している場合、コンパイラはその後、警告を発することができるということですスイッチ式の定数値でとおり場合

FileType type; 
// ... 
switch (type) { 
    case TextFile: 
     // ... 
} 

Iは、(この例ではファイルの異なる種類)既存の値に関連する別の定数値を追加することを決定し、事実上すべてのコンパイラウィルswitch文で新しい値が処理されないため、警告が発行されます。

代わりに 'int'と定数を使用していた場合、コンパイラは警告を出す機会がありません。

5

"enum hack"を使用する唯一の理由は、古いコンパイラが、あなたの質問で言うように、クラス内のconst定義をサポートしていないことです。ですから、あなたのコードが古いコンパイラに移植されていると思わない限り、constが必要なconstを使うべきです。

1

移植性は、enumを使用する正当な理由はです。あなたのコンパイラが "static const int S = 10"をサポートしているかどうか心配する必要がないので、それは素晴らしいです。

また、静的変数はどこかで定義する必要があります宣言されているように、enum値は宣言されていなければなりません。

+0

宣言に整数定数式初期化子が含まれていてもルールが非常に濁っている場合、整数型の 'static const'値を定義する必要はありません。私の答えを見てください。 –

5

enumの使用には利点があります。あなたは、たとえば、定義ので、もし列挙型は、タイプです:

enum EnumType { EnumValue1 = 10, EnumValue2 = 20 ... }; 

と次のような機能を持っている:あなたが列挙EnumTypeのメンバーを渡している

void Function1(EnumType Value) 

コンパイラのチェックをそのため、パラメータValueの有効な値だけがEnumValue1とEnumValue2になります。あなたが関数に(任意のint型、定数、変数またはリテラル)のintを渡しているコンパイラのチェックを定数を使用して

void Function1(int Value) 

に機能を変更した場合。

列挙型は、関連するconst値をグループ化するのに適しています。 const値が1つしかない場合、私は何の利点も見ません。

2

これらの2つの違いがあります。 Enumsは私が知る限り、アドレスを持っていません。静的なconst intは行うが。だから誰かがconst static intのアドレスを取得してconstをキャストした場合、その値を変更することができます(constだと思うのでコンパイラは変更を無視するかもしれません)。これはもちろん純粋な悪ですが、あなたはそれを行うべきではありませんが、コンパイラはそれを防ぐことはできません。これは列挙型では発生しません。

もちろん、あなたが(何らかの理由で)そのconstのアドレスが必要な場合は、static const intが必要です。

短い列挙型はrvalueですが、const static intは左辺値です。詳細は、http://www.embedded.com/story/OEG20011129S0065を参照してください。

+0

クライアントは静的const intのメンバ変数のアドレスを定義なしで受け取ることができません。しかし、Rvalue/lvalueの区別はあります。 –

+0

クライアントは、クラスを維持し、後でコードを追加する人はいません。 –

関連する問題