栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Item 10: Prefer scoped enums to unscoped enums.

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Item 10: Prefer scoped enums to unscoped enums.

Item 10: Prefer scoped enums to unscoped enums.

减少名称污染有强类型前向声明unscoped enums 的优势

Effective Modern C++ Item 10 的学习和解读。

一般来说,定义在花括号中的对象,其作用域也在花括号内,但是 C++98 风格的枚举(enums)类型却不遵从这一规则:

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

上面这种将枚举成员暴露在其花括号作用域外面的方式,官方称为无作用域限制的枚举(unscoped enums)。C++11 提供不暴露枚举成员的枚举类型:有作用域限制的枚举(scoped enums)。

enum class Color { black, white, red }; // black, white, red are scoped to Color
auto white = false;                     // fine, no other
减少名称污染

从上面的两个例子,可以看到 scoped enums 可以减少因作用域限制导致的名称污染,这是 scoped enums 的第一个优点。

有强类型

scoped enums 的第二个优点是其成员有强类型,不会发生隐式类型转换。看个例子:

enum Color { black, white, red }; // unscoped enum
std::vector  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 则不会发生隐式类型转换,上面的例子的 Color 修改成 scoped enums 方式,则会产生编译报错:

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
…
}

如果你一定要将 Color 转换为其他类型,可以使用显示类型转换:

if (static_cast(c) < 14.5) { // odd code, but it's valid
auto factors = primeFactors(static_cast(c)); // suspect, but it compiles
…
}
前向声明

scoped enums 的第三个优点是其可以前向申明,也即枚举名可以在没有指定其成员前进行申明。

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

其实,说 unscoped enums 不支持前向申明是不严谨的,其实在 C++11 中,它也可以前向申明,只不过不支持上面例子这样的前向申明,要想让它可以前向申明,还需要进行一点修改而已。所谓的前向申明,其本质就是告诉编译器目标是什么类型。

这里有一个事实,那就是unscoped enums 类型其实不是一个 enums,它的实际类型是编译器进行选择决定的。 scoped enums 之所以能够前向申明,是因为它的默认潜在类型(underlying type)是 int

enum Color { black, white, red };

对于上面代码,编译可以将 Color 类型选择成 char 就足够了。

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

但是,对于上面这段代码,编译器可能需要将 Status 类型选择成 int

总之,对于有作用域的枚举体的潜在类型是已知的,对于没有作用域的枚举体,你可以指定它。

对于 scoped enums ,默认的潜在类型为 int,当然你也可以进行更改:

enum class Status; // underlying type is int

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

对于 unscoped enums,指定了潜在类型,则可以前向申明:

enum Color: std::uint8_t; // fwd decl for unscoped enum; underlying type is std::uint8_t
unscoped enums 的优势

上面介绍了 scoped enumsunscoped enums 的几个优点。其实,unscoped enums 也有它自己的优势。看下面的例子:

using UserInfo = // type alias; see Item 9
std::tuple ; // reputation 

虽然注释说明了元组每个部分代表的含义,但是,当你遇到下面的代码时候,你可能还是记不清楚元组的第一个元素代表的是啥:

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

如果使用 unscoped enums 修改上面的代码,可以避免这个问题:

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

这里,UserInfoFieldsstd::get() 要求的 std::size_t 的隐式类型转换。要是使用 scoped enums 则代码要冗余的多:

enum class UserInfoFields { uiName, uiEmail, uiReputation };
UserInfo uInfo; // as before
…
auto val =
std::get(UserInfoFields::uiEmail)>(uInfo);

总结下:

C++98 风格的 enumunscoped enumscoped enums 的枚举成员仅仅对枚举体内部可见。只能通过类型转换( cast )转换为其他类型。scopded enumsunscoped enum 都支持指定潜在类型。scoped enum 默认潜在类型是 intunscoped enum 没有默认的潜在类型。scoped enum 总是可以前置声明的。unscoped enum 只有当指定潜在类型时才可以前置声明。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/737823.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号