枚举在范围外的整数初始化



我在读Bjarne Stroustrup的《c++导览》(2 nd edition)。在第2.5章中,他用下面的例子讨论了枚举:

enum class Color {red,blue,green};

在同一章中,他说允许用其底层类型(默认为int)的值初始化enum,并给出了以下示例:

Color x = Color{5}; //OK, but verbose
Color y {6};        //Also OK

我测试了,这当然可以编译。然而,我对用5或6初始化枚举的含义有点困惑,这超出了"范围"。(0-2)的颜色。在上面的例子中,x和y的实际值是多少?通过测试,它既不是"红色",也不是"绿色"。或"blue".

作为后续问题,为什么这个"超出范围"?允许初始化枚举?这似乎不太明智。

注意,在c++ 11中不支持枚举的整数初始化,但只在c++ 17及以后的版本中支持。

这来自C语言:枚举类型是花哨的整数。枚举的名称很方便,但它们并没有定义该类型可以表示的每个值。

不过,枚举类型最常见的用途可能是作为简单的常量列表:
enum state [
off,
starting,
running,
shutting_down,
out_of_service
};

枚举数的取值为:off== 0、starting== 1、running== 2、shutting_down== 3、out_of_service== 4。

但是,形式上,您不受这些值的限制。有时还会有一些有趣的值组合:

enum color {
red   = 0b0001,
green = 0b0010,
blue  = 0b0100
};

这些枚举数的值都经过精心设计,使得每个枚举数都使用不同的位;这使得我们可以很容易地组合值。

例如,颜色"purple"是红色和蓝色的组合。将红色(0b0001)和蓝色(0b0100)的位组合在一起,我们得到了一个包含两个位的值:0b0101。这是值5,它不是命名值之一。但是存储这个值是可以的:

color x = red | blue;   // x represents the value of purple
std::cout << x << 'n'; // displays 5

(我没有编译这个,因为我没有编译器在这台笔记本电脑上,所以你可能需要一个强制转换在这里)

相似的,

color y = red | green;  // y represents the value of yellow
std::cout << y << 'n'; // displays 3

可以存储哪些值的规则有点复杂,但基本上,如果位在那里,就可以使用它们。

这样做显然可以让您存储代表多个事物的值,但它也允许您查询这些事物:

bool has_blue(color c) { return c & blue; }
assert(has_blue(x));
assert(!has_blue(y));

因此,基本上,这允许您在需要存储和查询数字字段时使用命名类型而不是通用整数类型。当然,你可以用普通的常量来做这些:

const int red    = 0b0001;
const int green  = 0b0010;
const int yellow = 0b0100;

并将它们组合为整数值:

int x = red | blue;
int y = red | green;

但是现在它们的类型都只是一个普通的int,不像color那样具有描述性。

为什么这是允许的

c++最基本的设计目标之一(我可能引用错了)就是Bjarne"不知道人们需要解决什么问题"。因此设计的语言允许你违反它的警戒线。

当这可能是有用的,有时你想要的东西是在一个组合的状态:

enum Color 
{ 
red = 1 << 0, 
blue = 1 << 1, 
green = 1 << 2 
};

所以5的有效值大于枚举中标记的最大值(4),并且可以同时表示绿色和红色。

相关内容

  • 没有找到相关文章

最新更新