为什么人们可以使用 C++ 中的枚举作为常量const
?
12 回答
Bruce Eckel 在Thinking in C++中给出了一个理由:
在旧版本的 C++ 中,
static const
类内部不支持。这意味着这const
对于类中的常量表达式是没有用的。然而,人们仍然想这样做,所以一个典型的解决方案(通常称为“enum hack”)是使用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; }
枚举是不同的类型,所以你可以做面向类型的事情,比如用它们重载:
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;
};
另一个可能的原因是,静态 const int 可能在运行时为其保留了内存,而枚举永远不会为它保留实际的内存位置,并将在编译时处理。请参阅此相关问题。
枚举在使用时更具描述性。考虑:
int f(int fg, int bg)
相对
int f(COLOR fg, COLOR bg)
此外,枚举提供了更多的类型安全性,因为
- 整数不能隐式转换为枚举类型
- 一种类型的枚举不能隐式转换为另一种类型的枚举
我喜欢可以与枚举一起使用的自动行为,例如:
enum {NONE, START, HEY, HO, LAST};
然后很容易循环到 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
};
...
};
枚举也可以用作类型名称。因此,您可以定义一个将枚举作为参数的函数,与将值定义为 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 };
};
出于这个原因,许多可移植库继续使用这种形式。
另一个原因是枚举可以用作一种方便的句法设备来将类常量组织成相关的和不相关的
class DirectorySearcher
{
enum options
{
showFiles = 0x01,
showDirectories = 0x02,
showLinks = 0x04,
};
};
对比
class Integer
{
enum { treatAsNumeric = true };
enum { treatAsIntegral = true };
enum { treatAsString = false };
};
使用枚举以简洁的方式记录有效选择,并允许编译器强制执行它们。
如果他们使用枚举存储全局常量,例如 Pi,那么我不知道他们的目标是什么。
一个原因是const
需要更多的输入:
enum { Val1, Val2, Val3 };
...相对...
const int Val1=0, Val2=1, Val3=2;