为什么比起无作用域枚举,更偏爱有作用域枚举呢?

摘要:本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误。谢谢! 博客已经迁移到 "这里啦" 一般情况下,
本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误。谢谢! 博客已经迁移到这里啦 一般情况下,在花括号中声明一个name(包括变量名,函数名),这个name的可见性会被限制在花括号的作用域内。对于在C++98风格的enum中声明的enum成员却不是这样。这些enum成员的name属于的作用域是enum所在作用域,这意味着在这个作用域中,不能拥有相同的name: enum Color { black, white, red }; //black,white,red //和Color在同一个作用域 auto white = false; //错误!white在这个 //作用域已经声明过了 所以事实上,这些enum成员name泄露到enum所在的作用域中去了,这导致官方对于这种enum给出了一个官方术语:unscoped。新的C++11中有一个与此相对应的版本:scoped enum,不会像这样让name泄露: enum class Color { black, white, red }; //black,white red //在Color作用域中 auto white = false; //好的,没其他white Color c = white; //错误!在这个作用域中没有 //一个叫“white”的enum成员 Color c = Color::white; //对的 auto c = Color::white; //也是对的(而且和Item 5的建议一样) 因为scoped enum通过“enum class”声明,它们有时候也被叫做enum类。 单是减少命名空间的污染就足够作为理由让我们更偏爱scoped enum了,但是scoped enum还有第二个压倒性的优点:它们的成员属于强类型。unscoped enum的成员能隐式转换到数值类型(然后,从数值类型,可以转换到浮点类型)。因此像下面这样,在语义上是扭曲的代码是完全有效的: enum Color { black, white, red}; //unscoped enum std::vector<std::size_t> //函数,返回x的素因数 primeFactors(std::size_t x); Color c = red; ... if(c < 14.5) { //把Color和double数比较(!) auto factors = //计算Color的素因数(!) primeFactors(c); ... } 然而,在”enum“后面添加一个简单的”class“,就能把unscoped enum转变为scoped enum,并且情况会发生很大的改变。这里没有从enum的成员到任何其它类型的隐式转换: enum class Color { black, white, red }; //scoped Color c = Color::red; ... if (c < 14.5) { //错误,不能把Color和double //数进行比较 auto factors = //错误,函数需要一个std::size_t primeFactors(c); //不能传一个Color进去 ... } 如果你真的想要把Color转换到不同的类型,你需要做的就是:使用cast把Color转换成你需要的类型: if(static_cast<double>(c) < 14.5) { //奇怪的代码,但是有效 auto factors = //可疑的,但是能通过编译 primeFactors(static_cast<std::size_t>(c)); ... } 比起unscoped enum,scoped enum看起来还有第三个优点,因为scoped enum可以前置声明。也就是,他们的name可以在声明的时候不定义(不明确它们的成员): enum Color; //错误 enum class Color; //对的 这是一个误导。在C++11中,unscoped enum也能前置声明,但是需要做一些额外的工作。这个工作源于一个事实,就是C++中的每个enum都有一个整形的基础类型,这个类型由编译器决定。
阅读全文