const
を使用できるのに、C++で列挙型を定数として使用するのはなぜですか?
列挙は、一連の関連定数を意味するため、関係に関する追加情報は、問題のモデルで役立つはずです。
Bruce Eckelが C++での考え方 に理由を示しています。
古いバージョンのC++では、
static const
はクラス内ではサポートされていませんでした。これは、const
がクラス内の定数式には役に立たないことを意味しました。しかし、人々はまだこれを望んでいたため、典型的な解決策(通常は「列挙型ハック」と呼ばれます)は、インスタンスなしでタグなしのenum
を使用することでした。列挙型は、コンパイル時にすべての値が確立されている必要があり、クラスに対してローカルであり、その値は定数式で使用できます。したがって、通常は次のようになります。#include <iostream> using namespace std; class Bunch { enum { size = 1000 }; int i[size]; }; int main() { cout << "sizeof(Bunch) = " << sizeof(Bunch) << ", sizeof(i[1000]) = " << sizeof(int[1000]) << endl; }
[編集]
Bruce Eckelのサイトをリンクするほうが公平だと思います: http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html 。
列挙型は別個の型であるため、列挙型をオーバーロードするなど、型指向の処理を実行できます。
enum Color { Red,Green,Blue };
enum Size { Big,Little };
void f( Color c ) {
}
void f( Size s ) {
}
int main() {
f( Red );
f( Big );
}
テンプレートのメタプログラミングを扱う際にも歴史的な理由があります。一部のコンパイラは、列挙型からの値を使用できますが、クラスをインスタンス化するための静的なconst intは使用できません。
template <int N>
struct foo
{
enum { Value = foo<N-1>::Value + N };
};
template <>
struct foo<0>
{
enum { Value = 0; }
};
今、あなたはより賢明な方法でそれを行うことができます:
template <int N>
struct foo
{
static const int Value = foo<N-1>::Value + N;
};
template <>
struct foo<0>
{
static const int Value = 0;
};
もう1つの考えられる理由は、静的なconst intが実行時にメモリを予約している可能性があるのに対し、列挙型は実際のメモリの場所を予約することはなく、コンパイル時に処理されることです。 この関連質問を参照してください。
列挙型を使用すると、よりわかりやすくなります。検討してください:
int f(int fg, int bg)
versus
int f(COLOR fg, COLOR bg)
さらに、列挙型はもう少しタイプセーフを提供します。
列挙型で使用できる自動動作が好きです、例えば:
enum {NONE, START, HEY, HO, LAST};
その後、最後までループするのは簡単で、新しい状態(または表現されるもの)が追加されると、ロジックが適応します。
for (int i = NONE; i < LAST; i++)
{
// Do stuff...
}
何かを追加...
enum {NONE, START, HEY, WEE, HO, LAST};
ループが適応します...
コンパイラベンダーがISO/IEC 14882:1998 C++標準を実装する前は、クラススコープで定数を定義する次のコードはコンパイルエラーを引き起こしていました。
class Foo {
static const int MAX_LEN = 80;
...
};
定数が整数型である場合は、クラス内の列挙型で定数を定義することで手間がかかります。
class Foo {
enum {
MAX_LEN = 80
};
...
};
列挙型は型名としても使用できます。したがって、enumをパラメーターとして取る関数を定義できます。これにより、const変数として定義された値や "int"のみを受け入れる関数と比較して、関数に引数として指定する必要がある値の種類がより明確になります。引数として。
検討してください:
enum my_new_fangled_type {
baz = 0,
meh = 1
};
void foo (my_new_fangled_type bar) // bar can be a value listed in the enum
{
...
}
対:
int const baz = 0;
int const meh = 1;
void foo (int bar) // what are valid values for bar?
{
...
}
一部のデバッガーは、デバッグ時に値ではなく列挙名を表示します。これは非常に役立ちます。 day_of_week = MONDAY
ではなくday_of_week = 1
の方が見たいと思っています。
古いコンパイラが真のクラス定数の宣言をサポートしていなかったことが原因の一部です
class C
{
const int ARealConstant = 10;
};
だからこれをしなければならなかった
class C
{
enum { ARealConstant = 10 };
};
このため、多くの移植可能なライブラリがこの形式を使用し続けています。
もう1つの理由は、列挙型はクラス定数を関連するものとそうでないものに編成するための便利な構文デバイスとして使用できることです
class DirectorySearcher
{
enum options
{
showFiles = 0x01,
showDirectories = 0x02,
showLinks = 0x04,
};
};
対
class Integer
{
enum { treatAsNumeric = true };
enum { treatAsIntegral = true };
enum { treatAsString = false };
};
Enumを使用すると、有効な選択肢が簡潔に文書化され、コンパイラーがそれらを強制できるようになります。
たとえばPiのような列挙型ストアグローバル定数を使用している場合、その目的が何であるかわかりません。