条款10:优先选用限定作用域的枚举类型,而非不限定作用域的枚举类型

C++中的枚举类型分为限定作用域(enum class)和不限定范围(enum)。不限定范围的枚举量可以污染命名空间,允许隐式类型转换,可能导致意外行为,如与整型比较。限定作用域枚举解决了这些问题,限制了枚举量的作用域,不允许隐式转换,并支持前置声明,降低了编译依赖性。指定底层类型能进一步控制枚举的存储需求。
摘要由CSDN通过智能技术生成

如果在一个大括号里面声明一个名字,则该名字的可见性就被限定在括号扩起来的作用域内。但是这个规则不适用于C++98风格的枚举类型中定义的枚举量;这些枚举量的名字属于包含着这个枚举类型的作用域,意味这在此作用域内不能有其他实体取相同的名字;

enum Color {black, white, red};		// black,white,red所在作用域和Color相同
auto white = false;					// 错误!white已经在范围内被申明过

这些枚举常量的名字泄漏到枚举类型所在作用域的这一事实,对应一个术语:“不限定范围的枚举类型”;它们在C++11中的对等物:”限定作用域的枚举类型“;


enum class Color {black, white, red};	// black,white,red所在作用域被限定在Color内
auto white = false;						// 没问题,范围内并无其他”white“

Color c = white;						// 错误!范围内无名为”white“的枚举量
Color c = Color::white;					// 无问题
auto c= Color::white;					// 无问题

限定作用域的枚举类型带来:(1)名字空间污染降低;(2)枚举量是更强类型的;不限范围的枚举类型中枚举量可以隐式转换成整数类型,这么一来,如下的语义怪胎却成为完全合法的了;

enum Color {black, white, red};			// 不限定范围的枚举类型
std::vector<std::size_t> primeFactors(std::size_t x);

Color c = red;
if (c < 14.5) {							// 将Color类型与double类型进行比较
    auto factors = primeFactors(c);
}

仅仅是把一个简简单单的class加到enum之后,语义就变得完全不同了,从限定作用域的枚举类型到任何其他类型都不存在隐式转换路进:

enum class Color {black, white, red};	// 限定范围的枚举类型

std::vector<std::size_t> primeFactors(std::size_t x){
    return std::vector<std::size_t>();
}

Color c = Color::red;
if (c < 14.5) {							// 错误!不能将Color类型和double类型数值比较
    auto factors = primeFactors(c);		// 错误!不能将Color类型传入要求std::size_t类型的参数
}

限定作用域相比不限定作用域的第三个优点就是可以进行前置声明,即其类型名字可以比其中枚举量先声明:

enum Color;			// 错误
enum class Color;	// 没问题

一切枚举类型在C++里都会由编译器来选择一个整数类型作为其底层类型;如:

enum Color {black, white, red};	

编译器会选择char作为其底层类型,因为只有三个值表示;但是有些枚举类型取值范围就大得多,如:

enum Status {
	good = 0,
	failded = 1,
	incomplete = 100,
	corrupt = 200,
	indeterminate = 0XFFFFFFFF
}

这里,需要表示的取值范围是从0到0xFFFFFFFF为了节省内存,编译器通常会为枚举类型选用足够表示枚举量取值的最小底层类型;
前置声明能力的缺失还是会造成一些弊端。其中之一就是它会增加编译依赖性:

enum Status {
	// ...
	audited = 500,
	//...
}

这里增加了一个枚举量audited,可能整个系统都会因此需要重新编译,即使只有一个函数用到了这个新的枚举量audited;而这种事情利用C++11中为枚举类型提供的前置声明能力即可破除;举例:

enum class Status;					// 前置声明
void  continueProcessing(Status s);// 采用前置声明的枚举类型

若头文件中包含了这些声明,则在Status定义发生了修订时,就不会要求重新编译,即使Status被修改了(如增加了一个audited枚举量),但是contineProcessing的行为未受影响(例如,由于continueProcessing并未使用audited),则coninueProcessing的实现也同样无须重新编译;

可是如果编译器需要在枚举类型被使用前就知晓其尺寸,为什么C++11中的枚举类型就可以就行前置声明,C++98中就不行呢?因为:限定作用域枚举类型的底层类型是已知的;而对于不限定范围的枚举类型,你也可以指定这个底层类型;

enum class Status;					// 底层类型是int
enum class Status:std::uint32_t; 	// Status的底层类型为std::uint32_t	

如果要指定不限定范围的枚举类型的底层类型,做法和限定作用域的枚举类型一样;这样做了以后,不限范围的枚举类型也能进行前置类型声明了:

enum Color:std::uint8_t;			// 不限定范围的枚举类型的前置声明,底层类型为std::uint8_t

底层类型指定同样也可以在枚举类型定义中进行:

enum class Status : std::uint32_t{...}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值