简体   繁体   English

枚举类型是无范围的,比枚举更喜欢枚举 class?

[英]The enum type is unscoped prefer enum class over enum?

and I'm new to C++ and I'm wondering if anyone can help me to understand why我是 C++ 的新手,我想知道是否有人可以帮助我理解为什么

enum difficulty { NOVICE, EASY, NORMAL, HARD, UNBEATABLE };
difficulty myDiffiuclty = EASY

and

enum shipCost { FIGHTER_COST = 25, BOMBER_COST, CRUISER_COST = 50 };
shipCost myShipCost = BOMBER_COST;

are underlined in green?有绿色下划线? it says it prefers enum class, but when I change it to enum class then它说它更喜欢枚举 class,但是当我将其更改为枚举 class 时

enum class difficulty { NOVICE, EASY, NORMAL, HARD, UNBEATABLE };
difficulty myDiffiuclty = EASY;

enum class shipCost { FIGHTER_COST = 25, BOMBER_COST, CRUISER_COST = 50 };
shipCost myShipCost = BOMBER_COST;

EASY becomes underlined in red and myShipCost is underlined in green, BOMBER_COST underlined in red and CRUISER_COST is underlined in red EASY 变为红色下划线,myShipCost 变为绿色下划线,BOMBER_COST 变为红色下划线,CRUISER_COST 变为红色下划线

const int ALIEN_POINTS = 150;
int aliensKilled = 10;
int score = aliensKilled * ALIEN_POINTS;
cout << "score: " << score << endl;

enum difficulty { NOVICE, EASY, NORMAL, HARD, UNBEATABLE };
difficulty myDifficulty = EASY;

enum shipCost { FIGHTER_COST = 25, BOMBER_COST, CRUISER_COST = 50 };
shipCost myShipCost = BOMBER_COST;
cout << "\nTo upgrade my ship to a cruiser will cost "
    << (CRUISER_COST - myShipCost) << " Resource Points.\n";

system("pause");
return 0;
enum class difficulty { NOVICE, EASY, NORMAL, HARD, UNBEATABLE };
difficulty myDiffiuclty = difficulty::EASY;

enum class shipCost { FIGHTER_COST = 25, BOMBER_COST, CRUISER_COST = 50 };
shipCost myShipCost = shipCost::BOMBER_COST;

with enum class , implicit conversion to/from integers is removed, and you have to scope the constants in it.使用enum class ,与整数的隐式转换被删除您必须 scope 中的常量。

This is considered an improvement.这被认为是一种改进。 Explicitly casting it back to an integer still works, but it doesn't happen by accident.将其显式转换回 integer 仍然有效,但这不是偶然发生的。

std::cout << "\nTo upgrade my ship to a cruiser will cost "
    << (static_cast<int>(shipCost::CRUISER_COST) - static_cast<int>(myShipCost)) <<
    " Resource Points.\n";

system("pause");
return 0;

once you are using enum class , you should rename them:一旦你使用enum class ,你应该重命名它们:

enum class difficulty { novice, easy, normal, hard, unbeatable };
difficulty myDiffiuclty = difficulty::easy;

enum class shipCost { fighter =25, bomber=30, cruiser = 50 };
shipCost myShipCost = shipCost::bomber;

as the ship part of the name is now in the enum , no need to repeat it in the constant.由于名称的ship部分现在在enum中,因此无需在常量中重复。 Similarly, because the names are scoped, you don't have to SHOUT them.同样,因为名称是有范围的,所以您不必SHOUT它们。

Note, however, if you are just using it to create constants and no intention to create a type, consider using something like:但是请注意,如果您只是使用它来创建常量而不打算创建类型,请考虑使用类似的东西:

namespace ship {
  namespace cost {
    constexpr int fighter = 25;
    constexpr int bomber = 30;
    constexpr int cruiser = 50;
  }
}

now we have ship::cost::fighter as an int that is compile-time calculated, instead of as an enum class .现在我们有ship::cost::fighter作为编译时计算的int ,而不是enum class

Now that you understand the difference, from the answers above, I'd like to point out a couple of places where the "new" way of doing things breaks down, and what you can do about it.既然您从上面的答案中了解了区别,我想指出几个“新”做事方式发生故障的地方,以及您可以做些什么。

Consider this (abbreviated) actual example I ran into, porting some audio software I wrote in C to modern C++ (C++17):考虑一下我遇到的这个(缩写)实际示例,将我在 C 中编写的一些音频软件移植到现代 C++(C++17):

typedef enum sample_type_e {
   sample_type_uint16,
   sample_type_double
}sample_type_t;

Now, the first thing to know is that the typedef here is no longer required;现在,首先要知道的是这里的 typedef 不再需要了; you can read more about that elsewhere.您可以在其他地方阅读更多相关信息。 Moving on...继续...

This code, compiled in Visual Studio 2019, will result in the error you describe.此代码在 Visual Studio 2019 中编译,将导致您描述的错误。

Now, one approach to fixing this would seem to be to move to the new syntax-- but watch what happens:现在,解决此问题的一种方法似乎是改用新语法——但请注意会发生什么:

enum class SampleType {
   uint16,
   double
}

Oops.哎呀。

That's not going to work-- double is a reserved word.那是行不通的—— double是保留字。 Now, you could, in exasperation, do this:现在,你可以愤怒地这样做:

enum class SampleType {
   uint16,
   type_double
}

...but that's not very consistent, and by the time you get to this: ...但这不是很一致,当你得到这个时:

enum class SampleType {
   type_uint16,
   type_double
}

...you have arguably achieved the exact opposite of at least one of the purported benefits of this new feature: being terse, where possible, without losing context. ...可以说,您已经实现了与此新功能的至少一个声称的好处完全相反的结果:尽可能简洁,而不会丢失上下文。

The nuisance in my supposedly-contrived but actually real-world example is that you can't scope a reserved word: they're always reserved.在我所谓的人为但实际上是真实的示例中,令人讨厌的是您不能 scope 保留字:它们始终是保留的。 (Tangent point of interest: there are languages where that is never true...) (切线兴趣点:有些语言永远不正确......)

This is called "being unlucky";这叫做“倒霉”; it happens a lot more often than language designers like to admit, and it always comes up when you don't have one of them in the room with you.它发生的频率比语言设计师愿意承认的要多得多,而且当你没有一个人在房间里时,它总是会出现。

So, if something like that happens to come up for you, and you just really don't like what the results of trying to use "class enum" wind up looking like, what do you do?所以,如果你遇到类似的事情,而你真的不喜欢尝试使用“类枚举”的结果,你会怎么做?

Well, it turns out you can probably make the entire original problem go away by using another language feature that is considered good practice to use wherever possible: namespacing.好吧,事实证明,您可以通过使用一种被认为是尽可能使用的良好实践的语言功能:命名空间来解决整个原始问题 go。 If I merely namespace that original declaration (minus the crufty typedef), I get:如果我只是命名该原始声明(减去繁琐的 typedef),我会得到:

namespace audiostuff {
    enum sample_type_e {
       sample_type_uint16,
       sample_type_double
    };
};

...and as long as any code using that stuff is either in the same namespace, or has ...只要任何使用这些东西的代码在同一个命名空间中,或者有

using namespace audiostuff;

at the top, or, alternately, uses is like this:在顶部,或者,使用是这样的:

audiostuff::sample_type_e my_sample_type_var;

...then, lo and behold, Visual Studio stops complaining-- and other compilers should as well. ...然后,你瞧,Visual Studio 不再抱怨了——其他编译器也应该如此。

The complaint, after all, is about reminding you that you should avoid cluttering up the global namespace-- especially by accident.毕竟,抱怨是为了提醒您应该避免弄乱全局命名空间——尤其是意外。 "class enum" is one way to do that, but using an explicit namespace is as well. “类枚举”是一种方法,但使用显式命名空间也是如此。

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

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