前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Moderen Cpp之Enumerations

Moderen Cpp之Enumerations

作者头像
高性能架构探索
发布2023-12-06 19:00:27
1020
发布2023-12-06 19:00:27
举报
文章被收录于专栏:技术随笔心得

自C++11起,引入了新的枚举,至此,C++支持两种枚举,如果将新引入的枚举成为scoped enumerations的话,那么之前的则成为unscoped enumerations

Unscoped enumerations

Unscoped enumerations称为无范围枚举,又称为标准枚举(当然是相对新引入的枚举来说),形如:

代码语言:javascript
复制
enum Colors{
 Res,
 Green,
 Blue
};

这个在C里面也支持,所以在此就不在做详细的使用说明,为了引入本文的主题,例子如下:

代码语言:javascript
复制
namespace MyNamespace {
  enum Colors {
    Red,
    Green,
    Blue
  };
}
 
int main() {
  MyNamespace::Colors color = MyNamespace::Red;
  int enumValue = MyNamespace::Colors::Red;
 
  enumValue = MyNamespace::Red + MyNamespace::Blue;
 
  return 0;
}

如果此时,由于项目的需要,引入了第二个枚举OtherColors,比较特殊的是OtherColors中有一个与枚举Colors中相同的枚举值Blue,如下:

代码语言:javascript
复制
namespace MyNamespace {
  enum Colors {
    Red,
    Green,
    Blue
  };
  
  enum OtherColors {
    Yellow,
    Blue
  };
}
 
int main() {
  MyNamespace::Colors color = MyNamespace::Red;
  int enumValue = MyNamespace::Colors::Red;
 
  enumValue = MyNamespace::Red + MyNamespace::Blue;
 
  return 0;
}

此时编译器会报如下错误:

代码语言:javascript
复制
<enum.cc>:10:5: error: 'Blue' conflicts with a previous declaration
   31 |     Blue
      |     ^~~~
<enum.cc>:5:5: note: previous declaration 'MyNamespace::Colors MyNamespace::Blue'
   26 |     Blue

而这也就是C++11之前的枚举称为Unscoped enumerations的原因,即枚举的值存在于其声明的任何范围内。

当然了,我们可以通过其他方式来解决,一种比较常见的方式是通过值+枚举名来实现:

代码语言:javascript
复制
namespace MyNamespace {
  enum Colors {
    ColorsRed,
    ColorsGreen,
    ColorsBlue
  };
 
  enum OtherColors {
    OtherColorsYellow,
    OtherColorsBlue,
  };
}

显然,这种方式其就是相当于换了枚举值的名字。这种实现方式可以解决前面编译器的报错,但是会降低代码的可读性,因此往往采用另外一种实现方式:

代码语言:javascript
复制
{
  enum Enum
  {
    Red,
    Green,
    Blue
  };
}
 
namespace OtherColors
{
  enum Enum
  {
    Yellow,
    Blue,
  };
}

int main() {
  Colors::Enum color = Colors::Red;
  return 0;
}

这种实现方式,在项目中很常见,代码也很干净,一目了然。尤其是在命名空间内,将枚举名称命名为Enum,那么无论是在声明一个变量、函数参数、或者函数返回值的时候,通过前缀Enum一眼就能看出来是个枚举。并且在访问枚举的成员时,可以通过其命名空间来进行访问(Colors::Red),这种解决冲突的方式清楚简洁,且不会对编译时间运行期造成影响。

PS:在后文中,将此类枚举成为标准枚举

Scoped enumerations

Scoped enumerations自C++11引入,使用形如enum class来进行声明,又称为强枚举。与前面所讲的标准枚举相比,强枚举是有作用域的,如果在同一个命名空间内,使用标准枚举可能会引发冲突,而如果使用强枚举,则不会,因为其引入了范围的概念,仍然是前面的例子,引入强枚举后:

代码语言:javascript
复制
namespace MyNamespace {
  enum class Colors {
    Red,
    Green,
    Blue
  };
  
  enum class OtherColors {
    Yellow,
    Blue
  };
}
 
int main() {
  MyNamespace::Colors color = MyNamespace::Colors::Red;
  return 0;
}

不过,需要注意的是,强枚举不能像标准枚举一样进行类型转换,即:

代码语言:javascript
复制
int color = MyNamespace::Colors::Red;

会报错如下:

代码语言:javascript
复制
error: cannot convert 'MyNamespace::Colors' to 'int' in initialization

如果非要进行类型转换,则可以考虑强制类型转换方式:

代码语言:javascript
复制
int coloe = static_cast<int>(MyNamespace::Colors::Red);

相信很多人跟我一样,想知道强枚举的实现方式,此次借助cppinsights来分析下,仍然是上面的代码:

代码语言:javascript
复制
namespace MyNamespace
{
  enum class Colors : int
  {
    Red, 
    Green, 
    Blue
  };
}

看了上面代码的第一眼,就好奇enum class Colors : int,莫非强枚举继承于int?针对这个疑问,查了相关资料,发现上面的**:int并不是继承于int,而是指定了枚举的基础类型int**,下面代码摘自于so:

代码语言:javascript
复制
#include <iostream>

enum class tiny : bool {
    one, two   
};

enum class bigger : long {
    some, lots   
};

int main(int argc, char *argv[])
{
    std::cout << sizeof(tiny::one) << '\n';    //prints 1
    std::cout << sizeof(bigger::some) << '\n'; //prints 8
}

以上~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-12-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 高性能架构探索 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Unscoped enumerations
  • Scoped enumerations
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档