当前位置:网站首页>Item 10: Prefer scoped enums to unscoped enums.

Item 10: Prefer scoped enums to unscoped enums.

2022-07-06 03:11:00 Wan Xi a Shuai

Effective Modern C++ Item 10 Learning and interpretation of .

Generally speaking , Objects defined in curly braces , Its scope is also in curly brackets , however C++98 Enumeration of styles (enums) Types do not follow this rule :

enum Color {
     black, white, red }; // black, white, red are in same scope as Color
auto white = false;               // error! white already declared in this scope

The above method of exposing enumeration members outside their curly bracket scope , Officially known as enumeration without scope restrictions (unscoped enums).C++11 Provide enumeration types that do not expose enumeration members : Enumeration with scope restrictions (scoped enums).

enum class Color {
     black, white, red }; // black, white, red are scoped to Color
auto white = false;                     // fine, no other

Reduce name pollution

From the two examples above , You can see scoped enums It can reduce name pollution caused by scope restrictions , This is a scoped enums The first advantage of .

There are strong types

scoped enums The second advantage of is that its members have strong types , There will be no implicit type conversion . Look at an example :

enum Color {
     black, white, red }; // unscoped enum
std::vector<std::size_t>  primeFactors(std::size_t x); 
Color c = red;if (c < 14.5) {
           // compare Color to double (!)
  auto factors = primeFactors(c); // compute prime factors of a Color (!) }

scoped enums Implicit type conversion does not occur , Of the above example Color Modified into scoped enums The way , Compilation error will be generated :

enum class Color {
     black, white, red }; // enum is now scoped
Color c = Color::red;if (c < 14.5) {
      // error! can't compare Color and double
auto factors = primeFactors(c);  // error! can't pass Color to function expecting std::size_t}

If you must Color Convert to other types , You can use display type conversion :

if (static_cast<double>(c) < 14.5) {
     // odd code, but it's valid
auto factors = primeFactors(static_cast<std::size_t>(c)); // suspect, but it compiles}

Forward statement

scoped enums The third advantage of is that it can be forward stated , That is, the enumeration name can be declared without specifying its members .

enum Color; // error!
enum class Color; // fine

Actually , say unscoped enums It is not rigorous not to support forward statements , Actually in C++11 in , It can also be forward stated , It just doesn't support the forward statement like the above example , To make it forward statement , It just needs a little modification . The so-called forward statement , Its essence is to tell the compiler what type of target is .

Here is a fact , That's it unscoped enums Type is not a enums, Its actual type is determined by the compiler . scoped enums The reason why we can go forward , Because of its default potential type (underlying type) yes int.

enum Color {
     black, white, red };

For the above code , Compile to Color The type is selected as char That's enough .

enum Status {
     good = 0,
failed = 1,
incomplete = 100,
corrupt = 200,
indeterminate = 0xFFFFFFFF
};

however , For the above code , The compiler may need to put Status The type is selected as int.

All in all , The potential types of scoped enumerators are known , For enumerations without scope , You can specify it .

about scoped enums , The default potential type is int, Of course, you can also make changes :

enum class Status; // underlying type is int

enum class Status: std::uint32_t; // underlying type for Status is std::uint32_t (from <cstdint>)

about unscoped enums, Potential types are specified , Then it can be stated forward :

enum Color: std::uint8_t; // fwd decl for unscoped enum; underlying type is std::uint8_t

unscoped enums The advantages of

It says scoped enums Than unscoped enums Several advantages of . Actually ,unscoped enums It also has its own advantages . See the following example :

using UserInfo = // type alias; see Item 9
std::tuple<std::string, // name
	       std::string, // email
	       std::size_t> ; // reputation 

Although the annotation explains the meaning of each part of the tuple , however , When you encounter the following code , You may still not remember what the first element of a tuple represents :

UserInfo uInfo; // object of tuple typeauto val = std::get<1>(uInfo); // get value of field 1

If you use unscoped enums Modify the above code , This problem can be avoided :

enum UserInfoFields {
     uiName, uiEmail, uiReputation };
UserInfo uInfo; // as beforeauto val = std::get<uiEmail>(uInfo); // ah, get value of email field

here ,UserInfoFields To std::get() Required std::size_t Implicit type conversion for . If used scoped enums Then the code is much more redundant :

enum class UserInfoFields {
     uiName, uiEmail, uiReputation };
UserInfo uInfo; // as beforeauto val =
std::get<static_cast<std::size_t>(UserInfoFields::uiEmail)>(uInfo);

Sum up :

  • C++98 Style enum yes unscoped enum .
  • scoped enums The enumeration members of are only visible inside the enumeration body . Only by type conversion ( cast ) Convert to other types .
  • scopded enums and unscoped enum Both support specifying potential types .scoped enum The default potential type is int .unscoped enum There is no default latent type .
  • scoped enum It can always be pre declared .unscoped enum You can pre declare only when you specify a potential type .
原网站

版权声明
本文为[Wan Xi a Shuai]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202132333133098.html