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

C++怎么解决不支持字符串枚举?

首先,有两种方法:使用命名空间和字符串常量与使用 enum class 和辅助函数。

表格直观展示

特性使用命名空间和字符串常量使用 enum class 和辅助函数
类型安全性低 - 编译器无法检查字符串有效性,运行时发现错误高 - 编译期类型检查,非法类型在编译期即可发现
性能低 - 字符串比较时间复杂度为 O(n),逐字符比较有开销高 - 枚举值比较时间复杂度为 O(1),查找效率高,平均查找为 O(1)
可维护性中 - 易于理解和使用,但字符串容易拼写错误高 - 易读易维护,枚举类型和映射关系可以方便管理和扩展
代码简洁性中 - 可能需要反复访问命名空间中的字符串常量高 - 代码简洁且易读,枚举结合辅助函数方便处理
安全性中 - 字符串误输入导致运行时错误高 - 通过类型检查避免运行时崩溃
易用性中 - 需要记住和管理字符串常量,容易犯拼写错误高 - 枚举值可以通过智能提示和自动补全,大幅减少错误

代码展示 

使用命名空间和字符串常量 

优点

  1. 直观和易于理解:字符串表示类型或状态非常直观,容易理解和使用。
  2. 与外部系统交互方便:许多外部系统或配置文件使用字符串表示状态或类型,直接使用字符串便于与这些系统交互。

缺点

  1. 类型不安全:任何字符串都可以传入,编译器无法检查其有效性,拼写错误会导致运行时错误。
  2. 性能开销较大:字符串比较和逐字符检查的时间复杂度为 O(n),性能较低,尤其是在处理长字符串时。
  3. 可维护性差:字符串常量需要在代码中多次引用,拼写错误不易发现,维护困难。
namespace ContainerType {const std::string SimpleView = "SimpleView";const std::string SimpleViewPage = "SimpleViewPage";const std::string ListView = "ListView";const std::string ListViewPage = "ListViewPage";const std::string Dialog = "Dialog";
}void handleContainerType(const std::string& type) {if (type == ContainerType::SimpleView) {std::cout << "Handling SimpleView" << std::endl;} else if (type == ContainerType::SimpleViewPage) {std::cout << "Handling SimpleViewPage" << std::endl;} else if (type == ContainerType::ListView) {std::cout << "Handling ListView" << std::endl;} else if (type == ContainerType::ListViewPage) {std::cout << "Handling ListViewPage" << std::endl;} else if (type == ContainerType::Dialog) {std::cout << "Handling Dialog" << std::endl;} else {std::cout << "Unknown type" << std::endl;}
}

使用 enum class 和辅助函数

优点

  1. 类型安全:编译器进行类型检查,非法类型在编译期即可发现,避免运行时错误。
  2. 性能高效:枚举值比较时间复杂度为 O(1),使用哈希表进行字符串到枚举的映射查找平均为 O(1),高效。
  3. 代码可维护性高:枚举值清晰明了,降低拼写错误风险,方便代码维护。
  4. 易于扩展:可以方便地添加新的枚举值和映射关系。

缺点

  1. 稍微复杂:需要维护枚举和映射关系,初次使用时可能需要更多理解。
enum class ContainerType {SimpleView,SimpleViewPage,ListView,ListViewPage,Dialog,Unknown
};// 辅助函数:字符串 -> ContainerType
ContainerType stringToContainerType(const std::string& typeStr) {static const std::unordered_map<std::string, ContainerType> stringToEnumMap = {{"SimpleView", ContainerType::SimpleView},{"SimpleViewPage", ContainerType::SimpleViewPage},{"ListView", ContainerType::ListView},{"ListViewPage", ContainerType::ListViewPage},{"Dialog", ContainerType::Dialog}};auto it = stringToEnumMap.find(typeStr);if (it != stringToEnumMap.end()) {return it->second;}return ContainerType::Unknown;
}void handleContainerType(ContainerType type) {switch (type) {case ContainerType::SimpleView:std::cout << "Handling SimpleView" << std::endl;break;case ContainerType::SimpleViewPage:std::cout << "Handling SimpleViewPage" << std::endl;break;case ContainerType::ListView:std::cout << "Handling ListView" << std::endl;break;case ContainerType::ListViewPage:std::cout << "Handling ListViewPage" << std::endl;break;case ContainerType::Dialog:std::cout << "Handling Dialog" << std::endl;break;default:std::cout << "Unknown type" << std::endl;break;}
}int main() {ContainerType type = ContainerType::SimpleView;handleContainerType(type);type = stringToContainerType("Dialog");handleContainerType(type);return 0;
}

开源项目magic_enum

magic_enum 是一个 C++17 的头文件库,提供了对枚举的静态反射功能。它允许你在不使用宏或样板代码的情况下,轻松地将枚举类型与字符串进行转换,并实现一系列有关枚举的高效操作。有如下类:

enum class Color { RED = 1, BLUE, GREEN, NONE };
功能描述示例代码
枚举值转字符串将枚举值转换为字符串auto color_name = magic_enum::enum_name(color);
字符串转枚举值将字符串转换为枚举值(不区分大小写、二元谓词比较)auto color = magic_enum::enum_cast<Color>(color_name);
auto color = magic_enum::enum_cast<Color>("green", magic_enum::case_insensitive);
auto color = magic_enum::enum_cast<Color>("green", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); });
整数转枚举值将整数转换为枚举值auto color = magic_enum::enum_cast<Color>(color_integer);
通过索引访问枚举值根据索引获取枚举值Color color = magic_enum::enum_value<Color>(i);
获取枚举值序列获取所有枚举值的序列constexpr auto colors = magic_enum::enum_values<Color>();
获取枚举元素数量获取枚举的元素个数constexpr std::size_t color_count = magic_enum::enum_count<Color>();
获取枚举值的整数获取枚举值对应的整数auto color_integer = magic_enum::enum_integer(color);
auto color_integer = magic_enum::enum_underlying(color);
获取枚举名称序列获取所有枚举值的名称序列constexpr auto color_names = magic_enum::enum_names<Color>();
获取枚举条目序列获取所有枚举值和名称的序列constexpr auto color_entries = magic_enum::enum_entries<Color>();
检查枚举是否包含某个值检查枚举类型是否包含某个值magic_enum::enum_contains(Color::GREEN);
magic_enum::enum_contains<Color>(2);
magic_enum::enum_contains<Color>("GREEN");
获取枚举值的索引获取枚举值在序列中的索引constexpr auto color_index = magic_enum::enum_index(Color::BLUE);
枚举的位运算支持对枚举类型进行位运算using namespace magic_enum::bitwise_operators;
`Flags flags = Flags::A
标志枚举支持对标志枚举进行特殊处理template <> struct magic_enum::customize::enum_range<Directions> { static constexpr bool is_flags = true; };
`auto name = magic_enum::enum_flags_name(Directions::Up
枚举类型的名称获取枚举类型的名称auto type_name = magic_enum::enum_type_name<decltype(color)>();
ENUM 类型换为在IO流的操作符为枚举添加 ostream 和 istream 的支持using magic_enum::iostream_operators::operator<<;
using magic_enum::iostream_operators::operator>>;
检查是否为无范围枚举判断类型是否为无范围枚举magic_enum::is_unscoped_enum<color>::value;
magic_enum::is_unscoped_enum_v<color>;
检查是否为范围枚举判断类型是否为范围枚举magic_enum::is_scoped_enum<direction>::value;
magic_enum::is_scoped_enum_v<direction>;
Bitwise 操作符为枚举类型提供位操作符using namespace magic_enum::bitwise_operators;
`Flags flags = Flags::A
静态存储枚举变量到字符串更轻量的编译时间和不限于 enum_range 的限制constexpr auto color_name = magic_enum::enum_name<color>();

一个简单的示例:

#include <iostream>
#include <string>
#include <magic_enum.hpp>enum class Color { RED = 1, BLUE, GREEN, NONE };int main() {// 枚举值转字符串Color color1 = Color::RED;std::cout << "Color 1: " << magic_enum::enum_name(color1) << std::endl;// 字符串转枚举值std::string color_name{"GREEN"};auto color2 = magic_enum::enum_cast<Color>(color_name);if (color2.has_value()) {std::cout << "Color 2: " << magic_enum::enum_name(color2.value()) << std::endl;}return 0;
}

遇到的问题

main.cpp:3:10: fatal error: 'magic_enum.hpp' file not found #include <magic_enum.hpp> ^~~~~~~~~~~~~~~~ 1 error generated.

解决方法:

  1. 下载并包含 magic_enum 库。你可以从 magic_enum 的 GitHub 页面上下载最新的版本:GitHub - Neargye/magic_enum: Static reflection for enums (to string, from string, iteration) for modern C++, work with any enum type without any macro or boilerplate code
  2. magic_enum.hpp 头文件放在你的项目的合适目录中,例如 include 目录。
  3. 编译 
g++ -std=c++17 -Iinclude main.cpp -o main

如果你使用 CMake 进行项目构建,可以通过 FetchContentmegic_enum 集成到你的项目中。

   cmake_minimum_required(VERSION 3.11)project(MyProject)include(FetchContent)FetchContent_Declare(magic_enumGIT_REPOSITORY https://github.com/Neargye/magic_enum.gitGIT_TAG v0.7.3)FetchContent_MakeAvailable(magic_enum)add_executable(main src/main.cpp)target_link_libraries(main PRIVATE magic_enum::magic_enum)

模拟实现magic_enum

#include <array>
#include <string>
#include <utility>
#include <string_view>template <typename E, E V>
constexpr auto PrettyName()
{std::string_view name{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2};name.remove_prefix(name.find_last_of(" ") + 1);if (name.front() == '(') name.remove_prefix(name.size());return name;
}template <typename E, E V>
constexpr bool IsValidEnum()
{return !PrettyName<E, V>().empty();
}template <int... Seq>
constexpr auto MakeIntegerSequence(std::integer_sequence<int, Seq...>)
{return std::integer_sequence<int, (Seq)...>();
}constexpr auto NormalIntegerSequence = MakeIntegerSequence(std::make_integer_sequence<int, 32>());template <typename E, int... Seq>
constexpr size_t GetEnumSize(std::integer_sequence<int, Seq...>)
{constexpr std::array<bool, sizeof...(Seq)> valid{IsValidEnum<E, static_cast<E>(Seq)>()...};constexpr std::size_t count = [](decltype((valid)) v) constexpr noexcept->std::size_t{auto cnt = std::size_t{0};for (auto b : v) if (b) ++cnt;return cnt;}(valid);return count;
}template <typename E, int... Seq>
constexpr auto GetAllValidValues(std::integer_sequence<int, Seq...>)
{constexpr std::size_t count = sizeof...(Seq);constexpr std::array<bool, count> valid{IsValidEnum<E, static_cast<E>(Seq)>()...};constexpr std::array<int, count> seq{Seq...};std::array<int, GetEnumSize<E>(NormalIntegerSequence)> values{};for (std::size_t i = 0, v = 0; i < count; ++i) if (valid[i]) values[v++] = seq[i];return values;
}template <typename E, int... Seq>
constexpr auto GetAllValidNames(std::integer_sequence<int, Seq...>)
{constexpr std::array<std::string_view, sizeof...(Seq)> names{PrettyName<E, static_cast<E>(Seq)>()...};std::array<std::string_view, GetEnumSize<E>(NormalIntegerSequence)> validNames{};for (std::size_t i = 0, v = 0; i < names.size(); ++i) if (!names[i].empty()) validNames[v++] = names[i];return validNames;
}template <typename E>
constexpr std::string_view Enum2String(E V)
{constexpr auto names = GetAllValidNames<E>(NormalIntegerSequence);constexpr auto values = GetAllValidValues<E>(NormalIntegerSequence);constexpr auto size = GetEnumSize<E>(NormalIntegerSequence);for (size_t i = 0; i < size; ++i) if (static_cast<int>(V) == values[i]) return names[i];return std::to_string(static_cast<int>(V));
}
#include "myenum.h"
#include <iostream>enum class Color
{RED,GREEN,BLUE,
};int main()
{Color c = Color::BLUE;std::cout << Enum2String(c) << std::endl;return 0;
}

 

相关文章:

C++怎么解决不支持字符串枚举?

首先&#xff0c;有两种方法&#xff1a;使用命名空间和字符串常量与使用 enum class 和辅助函数。 表格直观展示 特性使用命名空间和字符串常量使用 enum class 和辅助函数类型安全性低 - 编译器无法检查字符串有效性&#xff0c;运行时发现错误高 - 编译期类型检查&#xf…...

中英双语介绍四大会计师事务所(Big Four accounting firms)

中文版 “四大会计师事务所”&#xff08;Big Four accounting firms&#xff09;是全球最具影响力和规模最大的四家专业服务公司&#xff0c;它们在审计、税务、咨询和财务咨询等领域占据着主导地位。这四家公司分别是普华永道&#xff08;PwC&#xff09;、德勤&#xff08;…...

ubuntu 查看联网配置

在Ubuntu中&#xff0c;你可以使用多种命令来查看联网配置。以下是一些常用的方法和命令&#xff1a; 查看网络接口配置&#xff1a; 使用 ip 命令可以查看网络接口的配置信息&#xff0c;包括IP地址、子网掩码等。 ip addr show或者&#xff0c;你也可以使用传统的 ifconfig 命…...

【数据分享】全国乡村旅游重点镇(乡)数据(Excel/Shp格式/免费获取)

之前我们分享过从我国文化和旅游部官网整理的2018-2023年我国50个重点旅游城市星级饭店季度经营状况数据&#xff08;可查看之前发布的文章&#xff09;&#xff01;文化和旅游部官网上也分享有很多与旅游相关的常用数据&#xff0c;我们基于官网发布的名单文件整理得到全国乡村…...

停车场小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;车主管理&#xff0c;商家管理&#xff0c;停车场信息管理&#xff0c;预约停车管理&#xff0c;商场收费管理&#xff0c;留言板管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;停车场信息…...

绿色金融相关数据合集(2007-2024年 具体看数据类型)

数据类型&#xff1a; 1.绿色债券数据&#xff1a;2014-2023 2.绿色信贷相关数据&#xff1a;2007-2022 3.全国各省及地级市绿色金融指数&#xff1a;1990-2022 4.碳排放权交易明细数据&#xff1a;2013-2024 5.绿色金融试点DID数据&#xff1a;2010-2023 数据来源&#…...

【matlab 项目工期优化】基于NSGA2/3的项目工期多目标优化(时间-成本-质量-安全)

一 背景介绍 本文分享了一个通用的项目工期优化的案例&#xff0c;决策变量是每个子项目的工期&#xff0c;优化目标是项目的完成时间最小&#xff0c;项目的总成本现值最小&#xff0c;项目的总安全水平最高&#xff0c;项目的总质量水平最高。采用的算法是NSGA2和NSGA3算法。…...

Python考前复习

选择题易错&#xff1a; python3不能完全兼容python2内置函数是python的内置对象之一&#xff0c;无需导入其他模块python中汉字变量合法&#xff0c;如“小李123”合法&#xff1b;但T-C不合法&#xff0c;因为有“-”集合无顺序&#xff0c;不能索引&#xff1b;range(5)[2]…...

虚拟机交叉编译基于ARM平台的opencv(ffmpeg/x264)

背景&#xff1a; 由于手上有一块rk3568的开发板&#xff0c;需要运行yolov5跑深度学习模型&#xff0c;但是原有的opencv不能对x264格式的视频进行解码&#xff0c;这里就需要将ffmpegx264编译进opencv。 但是开发板算力有限&#xff0c;所以这里采用在windows下&#xff0c;安…...

react之错误边界

错误边界实质是指什么 实际上是组件 错误边界捕获什么时候的错误 在渲染阶段的错误 错误边界捕获的是谁的错误 捕获的是子组件的错误 错误边界不能捕获什么错误 1、不能捕获异步代码 2、不能捕获事件处理函数 3、不能捕获服务端渲染 4、不能捕获自身抛出的错误 错误…...

openEuler系统之使用Keepalived+Nginx部署高可用Web集群

Linux系统之使用Keepalived+Nginx部署高可用Web集群 一、本次实践介绍1.1 本次实践简介1.2 本次实践环境规划二、keepalived介绍2.1 keepalived简介2.2 keepalived主要特点和功能2.3 使用场景三、Keepalived和Nginx介绍3.1 Nginx简介3.2 Nginx特点四、master节点安装nginx4.1 安…...

基于图像处理的滑块验证码匹配技术

滑块验证码是一种常见的验证码形式&#xff0c;通过拖动滑块与背景图像中的缺口进行匹配&#xff0c;验证用户是否为真人。本文将详细介绍基于图像处理的滑块验证码匹配技术&#xff0c;并提供优化代码以提高滑块位置偏移量的准确度&#xff0c;尤其是在背景图滑块阴影较浅的情…...

【JavaEE精炼宝库】文件操作(1)——基本知识 | 操作文件——打开实用性编程的大门

目录 一、文件的基本知识1.1 文件的基本概念&#xff1a;1.2 树型结构组织和目录&#xff1a;1.3 文件路径&#xff08;Path&#xff09;&#xff1a;1.4 二进制文件 VS 文本文件&#xff1a;1.5 其它&#xff1a; 二、Java 操作文件2.1 方法说明&#xff1a;2.2 使用演示&…...

常用排序算法_06_归并排序

1、基本思想 归并排序采用分治法 (Divide and Conquer) 的一个非常典型的应。归并排序的思想就是先递归分解数组&#xff0c;再合并数组。归并排序是一种稳定的排序方法。 将数组分解最小之后&#xff08;数组中只有一个元素&#xff0c;数组有序&#xff09;&#xff1b;然后…...

14-8 小型语言模型的兴起

过去几年&#xff0c;我们看到人工智能能力呈爆炸式增长&#xff0c;其中很大一部分是由大型语言模型 (LLM) 的进步推动的。GPT-3 等模型包含 1750 亿个参数&#xff0c;已经展示了生成类似人类的文本、回答问题、总结文档等能力。然而&#xff0c;虽然 LLM 的能力令人印象深刻…...

【Linux】:进程创建与终止

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关Linux程序地址空间的相关知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从…...

横截面交易策略:概念与示例

数量技术宅团队在CSDN学院推出了量化投资系列课程 欢迎有兴趣系统学习量化投资的同学&#xff0c;点击下方链接报名&#xff1a; 量化投资速成营&#xff08;入门课程&#xff09; Python股票量化投资 Python期货量化投资 Python数字货币量化投资 C语言CTP期货交易系统开…...

4.2 投影

一、投影和投影矩阵 我们以下面两个问题开始&#xff0c;问题一是为了展示投影是很容易视觉化的&#xff0c;问题二是关于 “投影矩阵”&#xff08;projection matrices&#xff09;—— 对称矩阵且 P 2 P P^2P P2P。 b \boldsymbol b b 的投影是 P b P\boldsymbol b Pb。…...

23种设计模式之装饰者模式

深入理解装饰者模式 一、装饰者模式简介1.1 定义1.2 模式类型1.3 主要作用1.4 优点1.5 缺点 二、模式动机三、模式结构四、 装饰者模式的实现4.1 组件接口4.2 具体组件4.3 装饰者抽象类4.4 具体装饰者4.5 使用装饰者模式4.6 输出结果&#xff1a; 五、 应用场景5.1 图形用户界面…...

数据结构--单链表实现

欢迎光顾我的homepage 前言 链表和顺序表都是线性表的一种&#xff0c;但是顺序表在物理结构和逻辑结构上都是连续的&#xff0c;但链表在逻辑结构上是连续的&#xff0c;而在物理结构上不一定连续&#xff1b;来看以下图片来认识链表与顺序表的差别 这里以动态顺序表…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

什么是VR全景技术

VR全景技术&#xff0c;全称为虚拟现实全景技术&#xff0c;是通过计算机图像模拟生成三维空间中的虚拟世界&#xff0c;使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验&#xff0c;结合图文、3D、音视频等多媒体元素…...