c++ enum 限域和未限域

发布时间 2023-06-09 15:16:38作者: _Explosion!

enum枚举类型在c/c++中较为常见,但是c++11以前,enum均为未限域枚举,即enum的花括号{}内的枚举名,其作用域是保护这个enum的作用域。

enum Color { black, white, red };   //black, white, red在Color所在的作用域
auto white = false;                 //错误! white早已在这个作用域中声明

而限域枚举(即通过enum class声明,也被称为枚举类)则不会发生这种现象

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;                  //也没问题

且需注意,限域枚举是强类型,不会被隐式转换,而未限域枚举会被隐式转换为整型或浮点型

enum Color { black, white, red };       //未限域enum

std::vector<std::size_t>                //func返回x的质因子
  primeFactors(std::size_t x);

Color c = red;
…

if (c < 14.5) {                         // Color与double比较 (!)
    auto factors =                      // 计算一个Color的质因子(!)
      primeFactors(c);
    …
}
enum class Color { black, white, red }; //Color现在是限域enum

Color c = Color::red;                   //和之前一样,只是
...                                     //多了一个域修饰符

if (c < 14.5) {                         //错误!不能比较
                                        //Color和double
    auto factors =                      //错误!不能向参数为std::size_t
      primeFactors(c);                  //的函数传递Color参数
    …
}

如果你真的很想执行Color到其他类型的转换,和平常一样,使用正确的类型转换运算符扭曲类型系统:

if (static_cast<double>(c) < 14.5) {    //奇怪的代码,
                                        //但是有效
    auto factors =                                  //有问题,但是
      primeFactors(static_cast<std::size_t>(c));    //能通过编译
    …
}

似乎比起非限域enum而言,限域enum有第三个好处,因为限域enum可以被前置声明。也就是说,它们可以不指定枚举名直接声明:

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