简体   繁体   English

枚举vs强类型枚举

[英]Enum vs Strongly typed enum

I am a beginner in C++ programming. 我是C ++编程的初学者。

Today I come across a new topic: strongly typed enum . 今天,我遇到了一个新话题:强类型enum I've researched it a bit but till now I am unable to find out why do we need this and what is the use of the same? 我已经研究了一下,但是直到现在我仍无法找出为什么我们需要这个,以及它的用途是什么?

For example if we have: 例如,如果我们有:

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

Why do we need to write: 为什么我们需要写:

enum class xyz{a, b, c};

What are we trying to do here? 我们要在这里做什么? My most important doubt is how to use it. 我最重要的疑问是如何使用它。 Could you provide a small example, which will make me understand. 您能否提供一个小例子,这会让我理解。

OK, first example: old-style enums do not have their own scope: 好,第一个示例:旧式枚举没有自己的范围:

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!

Second, they implicitly convert to integral types, which can lead to strange behaviour: 其次,它们隐式转换为整数类型,这可能导致奇怪的行为:

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

Finally, you can specify the underlying integral type of C++11 enums: 最后,您可以指定C ++ 11枚举的基础整数类型:

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

Previously, the underlying type was not specified, which could cause compatibility problems between platforms. 以前,未指定基础类型,这可能会导致平台之间的兼容性问题。 Edit It has been pointed out in comments that you can also specify the underlying integral type of an "old style" enum in C++11. 编辑注释中已经指出,您还可以在C ++ 11中指定“旧式”枚举的基础整数类型。

There's a good article about enums at this IBM page , it's very detailed and well-written. 此IBM页面上有一篇关于枚举的很好的文章,它非常详细且写得很好。 Here are some important points in a nutshell: 简而言之,这是一些重要点:

The scoped enums solve most of the limitations incurred by regular enums: complete type safety, well-defined underlying type, scope issues, and forward declaration. 作用域枚举解决了常规枚举所带来的大多数限制:完整的类型安全性,定义明确的基础类型,作用域问题和前向声明。

  • You get type safety by disallowing all implicit conversions of scoped enums to other types. 通过禁止将范围枚举的所有隐式转换为其他类型,可以确保类型安全。
  • You get a new scope, and the enum is not anymore in the enclosing scope, saving itself from name conflicts. 您将获得一个新的作用域,而该枚举不再位于封闭的作用域中,从而避免了名称冲突。
  • Scoped enums gives you the ability to specify the underlying type of the enumeration, and for scoped enums, it defaults to int if you choose not to specify it. 范围枚举使您能够指定枚举的基础类型,对于范围枚举,如果选择不指定,则默认为int。
  • Any enum with a fixed underlying type can be forward declared. 任何具有固定基础类型的枚举都可以向前声明。

Values of enum class is really of type enum class , not underlying_type as for C-enums. enum class值实际上是enum class类型,而不是C-enums的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);

The enum classes ("new enums", "strong enums") address three problems with traditional C++ enumerations: 枚举类(“新枚举”,“强枚举”)解决了传统C ++枚举的三个问题:

  1. conventional enums implicitly convert to int , causing errors when someone does not want an enumeration to act as an integer. 传统的enums隐式转换为int ,当有人不希望枚举充当整数时会导致错误。
  2. conventional enums export their enumerators to the surrounding scope, causing name clashes. 传统的enums将其枚举数导出到周围的范围,从而引起名称冲突。
  3. The underlying type of an enum cannot be specified, causing confusion, compatibility problems, and makes forward declaration impossible. enum的基础类型无法指定,从而导致混乱,兼容性问题,并使前向声明变得不可能。

enum class ("strong enums") are strongly typed and scoped: 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

As shown, traditional enums work as usual, but you can now optionally qualify with the enum's name. 如图所示,传统枚举像往常一样工作,但是您现在可以选择使用枚举的名称进行限定。

The new enums are "enum class" because they combine aspects of traditional enumerations (names values) with aspects of classes (scoped members and absence of conversions). 新的枚举是“枚举类”,因为它们将传统枚举的各个方面(名称值)与类的各个方面(作用域成员和无转换)结合在一起。

Being able to specify the underlying type allow simpler interoperability and guaranteed sizes of enumerations: 能够指定基础类型可以简化互操作性并保证枚举的大小:

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

It also enables forward declaration of 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

The underlying type must be one of the signed or unsigned integer types; 基础类型必须是有符号或无符号整数类型之一; the default is int . 默认值为int

In the standard library, enum classes are used for: 在标准库中, enum类用于:

  1. Mapping systems specific error codes: In <system_error> : enum class errc ; 映射系统特定的错误代码:在<system_error>enum class errc
  2. Pointer safety indicators: In <memory> : enum class pointer_safety { relaxed, preferred, strict }; 指针安全指示符:在<memory>enum class pointer_safety { relaxed, preferred, strict };
  3. I/O stream errors: In <iosfwd> : enum class io_errc { stream = 1 }; I / O流错误:在<iosfwd>enum class io_errc { stream = 1 };
  4. Asynchronous communications error handling: In <future> : enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied }; 异步通信错误处理:在<future>enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };

Several of these have operators, such as == defined. 其中一些具有运算符,例如==定义。

Enum Scope 枚举范围

Enumerations export their enumerators to the surrounding scope. 枚举将其枚举数导出到周围的范围。 This has two drawbacks. 这有两个缺点。 First, it can lead to name clashes, if two enumerators in different enums declared in the same scope have the same name; 首先,如果在同一作用域中声明的不同枚举中的两个枚举器具有相同的名称,则可能导致名称冲突; second, it's not possible to use an enumerator with a fully qualified name, including the enum name. 其次,不可能使用具有完全限定名称(包括枚举名称)的枚举器。

enum ESet {a0, a, a1, b1, c3};
enum EAlpha{a, b, c}

select = ESet::a; // error
select = a;       // is ambigious

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM