枚举与强类型枚举



我是C++编程的初学者。

今天我遇到了一个新的话题:强类型enum。我对它进行了一些研究,但到目前为止,我还无法找出我们为什么需要它,它有什么用?

例如,如果我们有:

enum xyz{a, b, c};
/*a = 0, b = 1, c = 2, (Typical C format)*/

为什么我们需要写:

enum class xyz{a, b, c};

我们在这里想做什么?我最怀疑的是如何使用它。你能举一个小例子吗?这会让我理解的。

好的,第一个例子:旧式枚举没有自己的作用域:

enum Animals {Bear, Cat, Chicken};
enum Birds {Eagle, Duck, Chicken}; // error! Chicken has already been declared!
enum class Fruits { Apple, Pear, Orange };
enum class Colours { Blue, White, Orange }; // no problem!

其次,它们隐含地转换为积分类型,这可能导致奇怪的行为:

bool b = Bear && Duck; // what?

最后,您可以指定C++11枚举的底层积分类型:

enum class Foo : char { A, B, C};

以前,未指定基础类型,这可能会导致平台之间的兼容性问题编辑注释中指出,您还可以在C++11中指定"旧式"枚举的底层积分类型。

在这个IBM页面上有一篇关于枚举的好文章,它非常详细,写得很好。简而言之,以下是一些重要的要点:

作用域枚举解决了常规枚举的大多数限制:完整的类型安全性、定义良好的底层类型、作用域问题和前向声明。

  • 您可以通过禁止所有作用域枚举到其他类型的隐式转换来获得类型安全性
  • 您得到了一个新的作用域,并且枚举不再在封闭作用域中,从而避免了名称冲突
  • 作用域枚举使您能够指定枚举的基本类型,对于作用域枚举,如果您选择不指定,则默认为int
  • 任何具有固定基础类型的枚举都可以正向声明

enum class的值实际上是enum class类型,而不是C-enum的underlying_type类型。

enum xyz { a, b, c};
enum class xyz_c { d, f, e };
void f(xyz x)
{
}
void f_c(xyz_c x)
{
}
// OK.
f(0);
// OK for C++03 and C++11.
f(a);
// OK with C++11.
f(xyz::a);
// ERROR.
f_c(0);
// OK.
f_c(xyz_c::d);

枚举类("new enums"、"strong enums")解决了传统C++枚举的三个问题:

  1. 传统的enums隐式转换为int,当有人不希望枚举充当整数时会导致错误
  2. 传统的enums将其枚举器导出到周围的作用域,从而导致名称冲突
  3. 无法指定enum的基础类型,这会导致混淆、兼容性问题,并导致无法进行前向声明

enum class("强枚举")是强类型和作用域:

enum Alert { green, yellow, orange, red }; // traditional enum
enum class Color { red, blue };   // scoped and strongly typed enum
// no export of enumerator names into enclosing scope
// no implicit conversion to int
enum class TrafficLight { red, yellow, green };
Alert a = 7;              // error (as ever in C++)
Color c = 7;              // error: no int->Color conversion
int a2 = red;             // ok: Alert->int conversion
int a3 = Alert::red;      // error in C++98; ok in C++11
int a4 = blue;            // error: blue not in scope
int a5 = Color::blue;     // error: not Color->int conversion
Color a6 = Color::blue;   // ok

如图所示,传统枚举照常工作,但您现在可以选择使用枚举的名称进行限定。

新枚举是"enum-class",因为它们将传统枚举的方面(名称值)与类的方面(作用域成员和缺少转换)结合在一起。

能够指定底层类型允许更简单的互操作性和有保证的枚举大小:

enum class Color : char { red, blue };  // compact representation
enum class TrafficLight { red, yellow, green };  // by default, the underlying type is int
enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U };   // how big is an E?
// (whatever the old rules say;
// i.e. "implementation defined")
enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U };   // now we can be specific

它还支持enums:的前向声明

enum class Color_code : char;     // (forward) declaration
void foobar(Color_code* p);       // use of forward declaration
// ...
enum class Color_code : char { red, yellow, green, blue }; // definition

基础类型必须是有符号或无符号整数类型之一;默认为CCD_ 10。

在标准库中,enum类用于:

  1. 映射系统特定错误代码:在<system_error>:enum class errc
  2. 指针安全指示灯:在<memory>中:enum class pointer_safety { relaxed, preferred, strict };
  3. I/O流错误:在<iosfwd>:enum class io_errc { stream = 1 };
  4. 异步通信错误处理:在<future>:enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };

其中有几个已经定义了运算符,例如==

枚举范围

枚举将其枚举器导出到周围的作用域。这有两个缺点。首先,如果在同一作用域中声明的不同枚举中的两个枚举器具有相同的名称,则可能导致名称冲突;其次,不可能使用具有完全限定名称(包括枚举名称)的枚举器。

enum ESet {a0, a, a1, b1, c3};
enum EAlpha{a, b, c}
select = ESet::a; // error
select = a;       // is ambigious

最新更新