[C++11] 枚举新特性完整解析

说明:C++11 关于新枚举的引入,主要有以下几个方面:

  • 强类型枚举(enum class):这是一种新的枚举类型,它提供了更强的类型检查。
  • 枚举类成员的底层类型:在枚举类中,可以明确指定枚举成员的底层整数类型。
  • 自动枚举值:这个特性允许枚举成员自动从 0 开始赋值,并且依次递增。
  • 枚举类型的字面量:枚举类型可以作为编译时常量使用,这使得枚举值可以在模板元编程和编译时决策中发挥作用。
  • 枚举类型的范围基于 std::underlying_type:通过 std::underlying_type,可以获取枚举类型的底层整数类型。
  • 枚举类型的比较操作:枚举类型的值可以与其他枚举值或布尔值进行比较。

接下来先了解为什么要引入这6个新特性?

1 C++11中为什么引入以上6个枚举的新特性

C++11 引入枚举的新特性主要是为了提高代码的安全性、清晰性、易用性和性能。以下是针对前面提到的六条规则分别引入新特性的原因:

  • 强类型枚举(enum class):引入强类型枚举的主要原因是为了提高类型安全性。在 C++11 之前,枚举类型(enum)的成员可以隐式转换为整型,这可能导致意外的类型转换错误和难以追踪的 bug。通过引入 enum class,C++11 强制要求显式转换,从而避免了这些类型安全问题。
  • 枚举类成员的底层类型:指定枚举类成员的底层类型可以让开发者有更多的控制权,使得枚举类型的设计更加灵活。这样的设计允许开发者根据需要选择最合适的整数类型,例如 uint8_t、int32_t 等,以存储枚举成员,从而优化内存使用和性能。
  • 自动枚举值:自动为枚举成员赋值的功能简化了枚举类型的声明,减少了代码的冗余。开发者不再需要手动为每个枚举成员指定数值,这不仅减少了编码工作量,也降低了出错的可能性。
  • 枚举类型的字面量:允许枚举类型作为字面量使用,提高了代码的表达能力和可读性。这使得枚举类型可以更方便地在模板元编程和其他编译时计算中使用,同时也使得代码更加简洁和易于理解。
  • 枚举类型的范围基于 std::underlying_type:通过提供 std::underlying_type 模板,C++11 使得对枚举类型的值进行迭代和比较变得更加容易。这为枚举类型的操作提供了更多的灵活性,同时也使得与枚举类型相关的算法和逻辑更加直观和一致。
  • 枚举类型的比较操作:提供对枚举类型的比较操作的支持,使得枚举类型的值可以与 bool 类型或其他枚举类型的值进行比较。这样的设计提高了枚举类型的实用性,使得它们可以更方便地用于条件语句、循环和其他控制结构中,同时也使得代码更加清晰和易于维护。

总的来说,C++11 中枚举类型的这些新特性都是为了提高代码的质量和可维护性,同时也使得枚举类型更加强大和易于使用。这些改进反映了 C++ 社区对于编写更安全、更高效和更易于理解的代码的持续追求。

2 枚举6大新特性使用详解

接下来,C++11 标准对枚举类型(enum)进行的6项扩展,详细解读如下。

2.1 强类型枚举(enum):

C++11 引入了强类型枚举,也称为枚举类(enum class),它提供了更好的类型安全性。与传统的枚举类型相比,枚举类的成员是强类型的,不能隐式转换为其他类型,这有助于避免意外的类型转换错误。参考代码如下:

enum class Color {Red, Green, Blue
};
// Color color = 1; // 错误:不能隐式转换为Color类型
Color color = Color::Red; // 正确:使用枚举类成员2.2 枚举类成员的底层类型

2.2 枚举类成员的底层类型

在C++11中,枚举类(enum class)允许开发者为枚举成员指定一个底层类型,这提供了更多的灵活性和精确性。以下是一些使用枚举类底层类型的案例。

2.2.1 使用 uint8_t 作为底层类型

参考代码如下:

enum class TrafficLight : uint8_t {Red = 1,Yellow,Green
};TrafficLight light = TrafficLight::Green;

在这个例子中,TrafficLight 枚举类的底层类型是 uint8_t,这意味着枚举成员将使用一个字节的无符号整数来存储。这适用于那些只需要少量值的枚举,例如交通信号灯状态。

2.2.2 使用 int16_t 作为底层类型

参考代码如下:

enum class TemperatureScale : int16_t {Celsius,Fahrenheit,Kelvin
};TemperatureScale scale = TemperatureScale::Celsius;

这里,TemperatureScale 枚举类的底层类型是 int16_t,它是一个16位的有符号整数。这个选择可能是因为温度尺度的值不需要太大的数值范围,但需要有符号整数来表示正负温度。

2.2.3 使用 uint32_t 作为底层类型表示颜色

参考代码如下:

enum class Color : uint32_t {Red = 0xFF0000,Green = 0x00FF00,Blue = 0x0000FF
};Color primaryColor = Color::Red;

在这个例子中,Color 枚举类使用 uint32_t 作为底层类型来表示颜色。每种颜色都有一个对应的RGB值,这些值通常用32位无符号整数表示。

2.2.4 使用 int8_t 作为底层类型表示方向

参考代码如下:

enum class Direction : int8_t {Up = -1,Down,Left,Right
};

Direction moveDirection = Direction::Up;这里,Direction 枚举类的底层类型是 int8_t,它是一个8位的有符号整数。这个选择适用于表示有限数量的方向,其中负值和正值可以用来表示相反的方向。

2.2.5 使用 uint64_t 作为底层类型表示大数值枚举

参考代码如下:

enum class LargeValue : uint64_t {Value1 = 10000000000000000ULL,Value2,Value3
};LargeValue value = LargeValue::Value1;

在这个例子中,LargeValue 枚举类的底层类型是 uint64_t,它是一个64位的无符号整数。这个选择适用于需要表示非常大数值的枚举,例如在处理大量数据或高性能计算时。

通过为枚举类指定底层类型,开发者可以根据枚举的实际用途和所需的数值范围来优化存储和性能。这些案例展示了如何根据不同的应用场景选择合适的底层类型。

2.3 自动枚举值

C++11 允许枚举类型的成员自动从 0 开始赋值,并依次递增。这简化了枚举值的定义,特别是当枚举成员数量较多时。参考代码如下:

enum class Direction {Up = 0,Right,Down,Left
};
// Direction::Up 的值为 0,Direction::Right 的值为 1,依此类推

2.4 枚举类型的字面量

枚举类型的字面量是 C++11 引入的一项特性,它允许枚举类型的成员作为编译时常量使用。这意味着枚举成员可以在模板元编程、常量表达式和需要编译时已知值的场景中使用。以下是几个使用枚举类型字面量的案例:

2.4.1 模板函数根据枚举类型处理不同的操作

参考代码如下:

template <typename T>
void process(T t) {// 通用处理
}template <>
void process<LogLevel>(LogLevel level) {switch (level) {case LogLevel::Info:   // 使用枚举字面量作为模板参数std::cout << "Information: ";break;case LogLevel::Warning:std::cout << "Warning: ";break;case LogLevel::Error:std::cout << "Error: ";break;}// 处理日志信息
}enum class LogLevel {Info,Warning,Error
};process<LogLevel::Info>(LogLevel::Info); // 调用模板函数

在这个例子中,LogLevel 是一个枚举类型,它的成员可以用作模板函数的参数。这允许函数根据日志级别采取不同的处理方式。

2.4.2 使用枚举字面量作为数组索引

参考代码如下:

enum class Direction {Up,Down,Left,Right
};const char* directionNames[] = {[Direction::Up] = "Up",[Direction::Down] = "Down",[Direction::Left] = "Left",[Direction::Right] = "Right"
};std::string name = directionNames[Direction::Right]; // 获取 "Right"

在这个例子中,枚举类型的成员作为数组索引使用,这使得数组的初始化更加直观和易于维护。

2.4.3 在编译时根据枚举值进行条件编译

参考代码如下:

#if defined(_DEBUG)
const int debugLevel = 1; // 调试模式下设置调试级别
#else
const int debugLevel = 0; // 非调试模式下关闭调试输出
#endifenum class DebugLevel {None = 0,Basic = 1,Detailed = 2
};void logMessage(DebugLevel level) {#if debugLevel >= DebugLevel::Basicstd::cout << "Log message: ";#endif// 打印日志消息
}

在这个例子中,枚举类型的值用于条件编译,这允许在不同的编译配置下控制代码的编译。

2.4.4 使用枚举字面量作为模板元编程的一部分

参考代码如下:

enum class LogLevel {None = 0,Info,Warning,Error,Fatal
};// 基本的 Logger 模板结构体
template <LogLevel L>
struct Logger {static void log(const std::string& message) {// 默认实现,根据日志级别输出不同的前缀std::cout << "[" << toString(L) << "] " << message << std::endl;}private:// 将 LogLevel 转换为字符串static std::string toString(LogLevel level) {switch (level) {case LogLevel::None:    return "None";case LogLevel::Info:   return "Info";case LogLevel::Warning: return "Warning";case LogLevel::Error:   return "Error";case LogLevel::Fatal:  return "Fatal";default:                return "Unknown";}}
};// 特化 Logger<LogLevel::Info> 以输出额外信息
template <>
struct Logger<LogLevel::Info> {static void log(const std::string& message) {std::cout << "[" << toString(LogLevel::Info) << "] [User ID: 12345] " << message << std::endl;}
};// 特化 Logger<LogLevel::Fatal> 以立即退出程序
template <>
struct Logger<LogLevel::Fatal> {static void log(const std::string& message) {std::cout << "[FATAL] " << message << std::endl;std::terminate();}
};int main() {//特化输出Logger<LogLevel::Info>::log("This is an informational message.");//正常输出Logger<LogLevel::Warning>::log("This is a warning message.");//特化输出Logger<LogLevel::Fatal>::log("This is a fatal error message.");return 0;
}

在上面的代码中,我们定义了一个 Logger 模板结构体,它有一个 log 静态成员函数,用于输出日志消息。我们还提供了两个特化版本:一个为 LogLevel::Info,它会输出一个额外的用户 ID;另一个为 LogLevel::Fatal,它会在输出日志后立即退出程序。

这个案例展示了如何使用枚举字面量作为模板元编程的一部分,允许我们根据不同的枚举值来特化模板函数或类。这种方法提供了极大的灵活性,使得我们可以根据枚举的不同值来定制不同的行为。

通过以上这些案例,我们可以看到枚举类型字面量在模板编程、条件编译和编译时常量计算中的灵活性和实用性。这些特性使得枚举类型成为 C++11 中更加强大和有用的工具。

2.5 关于std::underlying_type

C++11 提供了 std::underlying_type 模板,它可以获取枚举类型的底层整数类型。这使得对枚举类型的值进行迭代和比较变得更加容易。参考代码如下:

enum class Direction : int8_t{Up = 0,Down,Left,Right
};Direction d = Direction::Up;
for (auto i = static_cast<std::underlying_type<Direction>::type>(0); i <= static_cast<std::underlying_type<Direction>::type(d) + 1; ++i) {// 遍历 Direction 的所有值
}

例子中std::underlying_type<Direction>::type 实际上就是int8_t,std::underlying_type 提供了枚举的底层整数类型,而 static_cast 用于在已知两个类型之间存在合法转换的情况下进行类型转换。它们经常一起使用,以便在枚举类型和其底层整数类型之间进行安全的转换。

2.6 枚举类型的比较操作

C++11 标准库提供了对枚举类型的比较操作的支持,使得枚举类型的值可以与bool类型或其他枚举类型的值进行比较。这提高了枚举类型的表达能力和易用性。参考代码如下:

#include <iostream>// 定义一个表示状态的枚举类型
enum class Status {Active,Inactive,Pending
};// 函数根据状态打印出不同的信息
void printStatusMessage(Status status) {if (status == Status::Active) {std::cout << "The status is active." << std::endl;} else if (status == Status::Inactive) {std::cout << "The status is inactive." << std::endl;} else if (status == Status::Pending) {std::cout << "The status is pending." << std::endl;} else {std::cout << "Unknown status." << std::endl;}
}// 检查状态是否为非活动状态,并打印相应的信息
void checkIfInactive(Status status) {// 直接将枚举值与 bool 类型进行比较if (!status) {std::cout << "The status is not active." << std::endl;}
}int main() {Status currentStatus = Status::Inactive;// 打印状态信息printStatusMessage(currentStatus);// 检查状态是否为非活动状态checkIfInactive(currentStatus);return 0;
}

checkIfInactive 函数中,我们使用了 ! 逻辑非运算符来检查 Status 枚举值是否为 InactivePending(这两个状态可以被视为非活动状态)。由于 InactivePending 在枚举中是第一个和第二个值,它们在 C++ 中默认对应于 false(值为 0)和 true(值为 1)。因此,当我们使用 !status 进行比较时,如果 statusActive(值为 2 或更高),条件将评估为 true,并打印出 "The status is not active." 信息。

这个例子展示了如何直接将枚举类型的值与 bool 类型进行比较,利用了枚举值在 C++ 中的隐式转换为整数的特性。这种比较操作在处理状态标志或需要根据枚举值的真假状态做出决策时非常有用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/818118.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多级缓存实现方案

多级缓存 传统的缓存策略一般是请求到达Tomcat后&#xff0c;先查询Redis&#xff0c;如果未命中则查询数据库&#xff0c;存在下面的问题&#xff1a; 请求要经过Tomcat处理&#xff0c;Tomcat的性能成为整个系统的瓶颈Redis缓存失效时&#xff0c;会对数据库产生冲击 Caff…

一维非线性扩展卡尔曼滤波|matlab的EKF程序|一维例程源代码

为了满足不同条件下的用途,编了一个简单的一维状态量下的EKF,后面准备出UKF和CKF的版本。 使用的系统是非线性的,以体现算法对于非线性系统的性能。(状态方程和观测方程均设计成非线性的) 程序运行截图 程序都在一个m文件里面,粘贴到matlab的编辑器就能运行,如果中文注…

项目——boost搜索引擎

今天我们来写一个boost搜索引擎&#xff01; &#xff08;后续如果有更新&#xff0c;这个博客也会更新&#xff09; gitee连接:boost搜索引擎: boost搜索引擎 首先我们要介绍一下我们这个项目&#xff0c;我们项目的目的是通过我们的搜索引擎能够通过关键字查找到对应的网页…

Vue 3 和 i18n 实现多语言

第一部分&#xff1a;准备工作 首先&#xff0c;我们需要创建一个基本的 Vue 3 应用。如果你对 Vue 3 不熟悉&#xff0c;别担心&#xff0c;我们将从头开始。打开你的命令行工具&#xff0c;执行以下命令&#xff1a; vue create i18n-app这将创建一个名为 “i18n-app” 的新…

【小迪安全2023】第23天:WEB攻防-Python考点CTF与CMS-SSTI模版注入PYC反编译

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

【JAVA基础篇教学】第十五篇:Java中Spring详解说明

博主打算从0-1讲解下java基础教学&#xff0c;今天教学第十五篇&#xff1a;Java中Spring详解说明。 Spring 框架是一个广泛应用于 Java 开发的轻量级、全栈式的企业应用开发框架&#xff0c;它提供了众多功能强大的模块&#xff0c;用于简化企业级应用程序的开发。下面详细说…

光纤收发器的注意事项

光纤收发器有各种不同的类别&#xff0c;而实际使用中最受关注的是根据光纤收发器的不同类别&#xff1a;SC连接器光纤收发器和FC/ST连接器光纤收发器。 当使用光纤收发器连接到不同的设备时&#xff0c;必须小心使用不同的端口。 1.光纤收发器与100Base TX设备&#xff08;交…

第二期书生浦语大模型训练营第三次笔记

RAG RAG是什么&#xff1f; RAG&#xff08;Retrieval Augmented Generation&#xff09;技术&#xff0c;通过检索与用户输入相关的信息片段&#xff0c;并结合外部知识库来生成更准确、更丰富的回答。解决 LLMs 在处理知识密集型任务时可能遇到的挑战, 如幻觉、知识过时和缺…

js所有的引用类型(数组,对象,函数)都具有对象的特性

Object 类型&#xff1a;这是最基础的对象类型&#xff0c;可以包含属性和方法&#xff0c;属性的键可以是字符串或者符号&#xff0c;属性值可以是任意类型的数据。 Array 类型&#xff1a;数组是特殊的对象&#xff0c;用于存储有序的数据集合。它提供了一些内置方法来操作这…

ssh 使用

ssh 使用 一、ssh 安装二、ssh 使用1. ssh 登录2. ssh-keygen 免密登录(1) ssh 生成密钥(2) 开启远程主机的密钥登陆(3) ssh 分发公钥 3. ssh-copy-id 复制公钥到远程主机4. scp 复制 系统环境: linux(ubuntu,debian,kali) 一、ssh 安装 sudo apt update sudo apt install op…

13015.交叉编译移植libz库

文章目录 1 背景2 交叉编译流程2.1 下载源码2.2 编译2.3 测试代码2.4 交叉编译app程序2.5 压缩及效率测试 1 背景 需要再app中使用压缩算法&#xff0c;不能直接移植gzip&#xff0c;gzip交叉编译得到gzip&#xff0c;应该使用libz代码 进行编译生成libz库. 2 交叉编译流程 …

面试手撕合集

82.删除排序链表中的重复元素II 定义单个指针 cur&#xff0c;指向虚拟头节点。如果 cur.next cur.next.next&#xff0c;说明 cur 后面的两个节点重复&#xff0c;例如 节点2 后面存在 2个节点3。我们令 节点2 -> 节点4&#xff0c;实现删除两个节点3的操作。 class Solut…

tcp 为什么要三次握手

TCP三次握手流程&#xff1a; 首先客户端发起请求&#xff0c;想服务端发送SYN报文服务端接收到客户端请求过后&#xff0c;产生SYNACK报文&#xff0c;并将SYNACK报文返回给客户端客户端收到SYNACK报文之后将此报文再发回服务端&#xff0c;至此三次握手完成&#xff0c;连接…

机器人方向控制中应用的磁阻角度传感芯片

磁阻传感器提供的输出信号几乎不受磁场变动、磁温度系数、磁传感器距离与位置变动影响&#xff0c;可以达到高准确度与高效能&#xff0c;因此相当适合各种要求严格的车用电子与工业控制的应用。所以它远比采用其它传感方法的器件更具有优势。 机器人的应用日渐广泛&#xff0…

Linux Debian安装教程

Debian 是一个免费的开源操作系统&#xff0c;是最古老的 Linux 发行版之一&#xff0c;于 1993 年由 Ian Murdock 创建。它采用了自由软件协议&#xff0c;并且由志愿者社区维护和支持。Debian 的目标是创建一个稳定、安全且易于维护的操作系统&#xff0c;以自由软件为基础&a…

吴恩达机器学习笔记:第 7 周-12支持向量机(Support Vector Machines)12.4-12.6

目录 第 7 周 12、 支持向量机(Support Vector Machines)12.4 核函数 1 第 7 周 12、 支持向量机(Support Vector Machines) 12.4 核函数 1 回顾我们之前讨论过可以使用高级数的多项式模型来解决无法用直线进行分隔的分类 问题&#xff1a; 为了获得上图所示的判定边界&…

电子元器件线上交易商城搭建的价值和必要性-加速度jsudo

随着科技的飞速发展&#xff0c;电子元器件行业正迎来前所未有的变革。为了满足市场对于电子元器件采购的便捷性、高效性和多样性的需求&#xff0c;电子元器件商城的开发显得尤为重要。本文将探讨电子元器件商城开发的重要性、主要功能以及它如何助力行业发展。 电子元器件商城…

gles+egl+drm+gbm实现开机动画

基于安卓开机动画修改 /* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the Li…

[后端开发] 过滤器相关注解

一、背景 使用Springboot框架开发后端&#xff0c;在鉴权的时候使用到了过滤器。但是在测试的过程发现&#xff0c;跨域的过滤器在过滤链中出现了两次&#xff0c;导致前端访问后端接口时报错&#xff1a;The Access-Control-Allow-Origin headers contains multiple values,b…