当前位置: 首页 > news >正文

[C++] enum 以及 enum class 简单用法

C语言风格枚举类型 enum


这是一个enum类型

enum LogType {
	OK,
	Info,
	Error
};

可以像这样指定enum的基础类型(默认类型是int),用英文来说就是underlying type

enum LogType : unsigned int {
	OK,
	Info,
	Error
};

继续升级,指定每个枚举元素具体的值

enum LogType : unsigned int {
	OK = 0x00,
	Info = 0x01,
	Error = 0x02
};

经典位掩码,即Bitmask写法

enum WindowFlags : unsigned int {
    None = 0x0000,
    NoMove = 0x0001,
    NoResize = 0x0002,
    NoSavedSettings = 0x0004
};
auto MySettings = NoMove | NoResize;

但是enum本质上其实是无范围枚举,即unscoped enumeration,很容易就会发现命名冲突问题

enum LogType {
	OK,
	Info,
	Error
}; // OK

enum StatusCode {
    OK,
    Forbidden
}; // OK?

auto res = LogType::OK; // Compiler doesn't know which OK to use even using :: to specify

想要解决这个问题并不难,我们可以外面套一层struct或者class

struct LogType {
    enum {
        OK,
        Info,
        Error
    };
};

class StatusCode {
    enum {
        OK,
        Forbidden
    };
};

auto res = LogType::OK; // OK!

但是这样似乎不太优雅,尤其是我们想将enum作为函数返回值的时候

struct StatusCode {
    enum {
        OK,
        Forbidden
    };
};

StatusCode foobar() {
    return StatusCode::OK; // Hey, don't do this!
};

C++风格枚举类型 enum class

为了解决以上种种问题,C++引入了enum class,这是一种范围枚举,即scoped enumeration,不存在命名冲突
用法和enum相似,无非就是在后面添加了一个struct或者class(等效)

enum struct LogType {
    OK,
    Info,
    Error
};

enum class StatusCode {
    OK,
    Forbidden
};

我们也可以像enum一样把enum class类型作为函数返回值(可以把它看作是一个类)

enum class StatusCode {
    OK,
    Forbidden
};

StatusCode foobar() {
    return StatusCode::OK;
};

值得注意的是,enum class并不支持隐式类型转换,即implicit type conversion
因此,enum class也并不能像enum那样直接进行位运算

enum class WindowFlags : unsigned int {
    None = 0x0000,
    NoMove = 0x0001,
    NoResize = 0x0002,
    NoSavedSettings = 0x0004
};

WindowFlags foobar() {
    return WindowFlags::None;
};
if (!foobar())
	exit(EXIT_FAILURE); // g++: expression must have bool type (or be convertible to bool)
auto MySettings = NoMove | NoResize; // g++: no operator "|" matches these operands
auto MySettings = static_cast<WindowFlags> (
    static_cast<unsigned int> (WindowFlags::NoMove) | static_cast<unsigned int> (WindowFlags::NoResize)); // OK

显示类型转换,即explicit type conversion似乎过于臃肿,但是我们可以重载一下enum class相关的operator,以下模板放在我们的enum class的命名空间内即可(具体细节此处不赘述,请自行查阅std::enable_if_t, std::is_enum_v)

template <typename enum_type, typename cast_type = std::size_t>
constexpr std::enable_if_t<std::is_enum_v<enum_type>, enum_type> operator& (enum_type x, enum_type y) {
    return static_cast<enum_type>
        (static_cast<cast_type> (x) & static_cast<cast_type> (y));
}

template <typename enum_type, typename cast_type = std::size_t>
constexpr std::enable_if_t<std::is_enum_v<enum_type>, enum_type> operator| (enum_type x, enum_type y) {
    return static_cast<enum_type>
        (static_cast<cast_type> (x) | static_cast<cast_type> (y));
}

template <typename enum_type, typename cast_type = std::size_t>
constexpr std::enable_if_t<std::is_enum_v<enum_type>, enum_type> operator^ (enum_type x, enum_type y) {
    return static_cast<enum_type>
        (static_cast<cast_type> (x) ^ static_cast<cast_type> (y));
}

template <typename enum_type, typename cast_type = std::size_t>
constexpr std::enable_if_t<std::is_enum_v<enum_type>, enum_type> operator~ (enum_type x) {
    return static_cast <enum_type> 
        (~static_cast<cast_type> (x));
}

template <typename enum_type, typename cast_type = std::size_t>
constexpr std::enable_if_t<std::is_enum_v<enum_type>, enum_type> operator&= (enum_type &x, enum_type y) {
    x = x & y;
    return x;
}

template <typename enum_type, typename cast_type = std::size_t>
constexpr std::enable_if_t<std::is_enum_v<enum_type>, enum_type> operator|= (enum_type &x, enum_type y) {
    x = x | y;
    return x;
}

template <typename enum_type, typename cast_type = std::size_t>
constexpr std::enable_if_t<std::is_enum_v<enum_type>, enum_type> operator^= (enum_type &x, enum_type y) {
    x = x ^ y;
    return x;
}

enum class严格意义上来说并不是一个常规意义上的class,所以无法通过重载自动转换为bool类型,但是我们可以手写一个any函数来判断位掩码

template <typename enum_type, typename cast_type = std::size_t>
constexpr std::enable_if_t<std::is_enum_v<enum_type>, bool> any(enum_type x) {
    return static_cast<cast_type> (x) == 0;
};

简单样例(已载入上述模板)

enum class WindowFlags : unsigned int {
    None = 0x0000,
    NoMove = 0x0001,
    NoResize = 0x0002,
    NoSavedSettings = 0x0004
};

auto MySettings = WindowFlags::NoMove | WindowFlags::NoResize;

if (any(MySettings)) { // To check if any flags are set
	/* do something */
}

参考链接

cppreference.com

相关文章:

  • Transformer 代码剖析6 - 位置编码 (pytorch实现)
  • Cursor+pycharm接入Codeuim(免费版),Tab自动补全功能平替
  • 支付宝 IoT 设备入门宝典(下)设备经营篇
  • 软件安全性测试类型分享,第三方软件测试机构如何进行安全性测试?
  • 建造者模式
  • 蓝(准备)
  • Python Cookbook-2.17 在目录树中改变文件扩展名
  • VSCode离线安装插件
  • 关于网页地图的坐标系
  • 《深度学习实战》第6集:扩散模型(Diffusion Models)与高质量图像生成
  • Ruby基础
  • 【免费】YOLO[笑容]目标检测全过程(yolo环境配置+labelimg数据集标注+目标检测训练测试)
  • Spring Boot 接口 JSON 序列化优化:忽略 Null 值的九种解决方案详解
  • Python--内置模块和开发规范(上)
  • DeepSeek可实现智能派工,提升售后服务效率
  • ubuntu部署gitlab-ce及数据迁移
  • 【北京迅为】iTOP-RK3568OpenHarmony系统南向驱动开发-第2章 内核HDF驱动框架架构
  • 【容器化】低版本docker拉取ubuntn 22.04镜像启动容器执行apt update提示 NO_PUBKEY 871920D1991BC93C
  • 腿足机器人之十四-强化学习SAC算法
  • 指针的进阶(提高篇)
  • 用中文模版可以做英文网站吗/网站seo软件
  • 重庆建设教育协会网站/网络营销推广的方式
  • 深圳市福田区香蜜湖街道/搜索优化指的是什么
  • 做ppt找图片网站/系统优化软件推荐
  • 咸阳做网站xymokj/上海百度推广电话
  • 网站建设初级工程师/电子商务seo名词解释