怎么解决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;
}

 

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

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

相关文章

基于正点原子FreeRTOS学习笔记——时间片调度实验

目录 一、时间片调度介绍 二、实验演示 1、宏修改 1.1、滴答定时器宏 1.2、调度器宏 2、实验程序 2.1.1、任务1&#xff0c;任务2不加临界区程序 2.1.2 实验现象 2.2.1、任务1&#xff0c;任务2加临界区程序 2.2.2 实验现象 一、时间片调度介绍 时间片&#xff1a;同…

[Cloud Networking] BGP

1. AS (Autonomous System) 由于互联网规模庞大&#xff0c;所以网络会被分为许多 自治系统&#xff08;AS-Autonomous system&#xff09;。 所属类型ASN名称IPv4 数量IPv6数量运营商ISPAS3356LEVEL3 - Level 3 Parent, LLC, US29,798,83273,301,954,048互联网企业AS15169GO…

vue+element-ui简洁完美实现个人博客“​响石潭 ​”

目录 一、项目介绍 二、项目截图 1.项目结构图 2.首页 3.生活 ​编辑 4.文章详情 ​编辑 5.关于我 ​编辑 ​编辑 三、源码实现 1.项目依赖package.json 2.项目启动 3.首页源码 四、总结 一、项目介绍 本项目在线预览&#xff1a;点击访问 参考官网&#xff1…

数据库操作语言(DML)

数据库操作语言&#xff08;DML&#xff09; 文章目录 数据库操作语言&#xff08;DML&#xff09;一、四种操作二、数据的插入&#xff08;增&#xff09;三、数据的删除&#xff08;删&#xff09;四、数据的修改&#xff08;改&#xff09;五、数据的查询&#xff08;查&…

STM32 中断编程入门

目录 一、中断系统 1、中断的原理 2、中断类型 外部中断 定时器中断 DMA中断 3、中断处理函数 中断标志位清除 中断服务程序退出 二、实际应用 中断控制LED 任务要求 代码示例 中断控制串口通信 任务要求1 代码示例 任务要求2 代码示例 总结 学习目标&…

如何理解MySql的MVCC机制

MVCC是什么 MySQL的MVCC机制&#xff0c;全称为多版本并发控制&#xff08;Multi-VersionConcurrency Control&#xff09;&#xff0c;是一种提高数据库并发性能的技术。MVCC的主要目的是在保证数据一致性的同时&#xff0c;提高数据库的并发性能。 它通过为每个读操作创建数…

技术赋能教育:校园3D电子地图与AR导航解决方案

随着高考的落幕&#xff0c;又一批新鲜血液即将注入大学校园。面对陌生的环境&#xff0c;如何快速适应、准确找到目标地点&#xff0c;成为新生们的一大难题。同时&#xff0c;对于学校而言&#xff0c;如何向报考人员直观展示校园环境&#xff0c;提供沉浸式参观体验&#xf…

Vue跨域获取ip和ip位置城市等归属地信息

由于端口设置与查询服务器不一致&#xff0c;所以不能直接从ip138网上抓取&#xff0c;只能跨域查询。实现跨域查询&#xff0c;简单的方法是使用jsonp方式&#xff0c;只支持get请求&#xff0c;同时也需要查询的服务器支持jsonp。这时找到了腾讯位置服务。参考文章&#xff0…

第 27 篇 : 搭建maven私服nexus

官网文档 1. 下载应该很慢, 最好是能翻墙 nexus-3.69.0-02-java8-unix.tar.gz 2. 上传到/usr/local/src, 解压及重命名 tar -zxvf nexus-3.69.0-02-java8-unix.tar.gz rm -rf nexus-3.69.0-02-java8-unix.tar.gz mv nexus-3.69.0-02 nexus ls3. 修改配置 cd /usr/local/sr…

2024最新版Redis常见面试题包含详细讲解

Redis适用于哪些场景&#xff1f; 缓存分布式锁降级限流消息队列延迟消息队 说一说缓存穿透 缓存穿透的概念 用户频繁的发起恶意请求查询缓存中和数据库中都不存在的数据&#xff0c;查询积累到一定量级导致数据库压力过大甚至宕机。 缓存穿透的原因 比如正常情况下用户发…

生命在于学习——Python人工智能原理(3.1.2)

一、概率基本知识 1.3 常见概型 1.3.1 古典概型 定义1 古典概型 若随机事件E满足如下两个条件&#xff1a; &#xff08;1&#xff09;样本空间S中只有有限个样本点。 &#xff08;2&#xff09;样本空间S中每个样本点发生都是等可能的。 这样的随机试验称为古典概型。 P(A)…

暑期大数据人工智能学习-企业项目试岗实训开营

暑期企业项目-试岗实训活动全面开启啦 跟张良均老师学大数据人工智能 不仅可以提供实习证明&#xff0c;有需要话也可以提供实习鉴定报告 √54个热门案例拆解 √40项目实战课程 √27个项目可选 √4个项目方向

企业本地大模型用Ollama+Open WebUI+Stable Diffusion可视化问答及画图

最近在尝试搭建公司内部用户的大模型&#xff0c;可视化回答&#xff0c;并让它能画图出来&#xff0c; 主要包括四块&#xff1a; Ollama 管理和下载各个模型的工具Open WebUI 友好的对话界面Stable Diffusion 绘图工具Docker 部署在容器里&#xff0c;提高效率 以上运行环境…

to_json 出现乱码的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

基于MIMO系统的预编码matlab性能仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 最小均方误差&#xff08;MMSE&#xff09;准则 4.2 量化准则 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 …

让围绕数据库构建大模型应用更简单方便--DB-GPT

DB-GPT的目的是构建大模型领域的基础设施&#xff0c;通过开发多模型管理(SMMF)、Text2SQL效果优化、RAG框架以及优化、Multi-Agents框架协作、AWEL(智能体工作流编排)等多种技术能力&#xff0c;让围绕数据库构建大模型应用更简单&#xff0c;更方便。 1 处理流程 DB-GPT系…

使用supportFragmentManager管理多个fragment切换

android studio创建的项目就没有一个简单点的框架&#xff0c;生成的代码都是繁琐而复杂&#xff0c;并且不实用。 国内的页面一般都是TAB页面的比较多&#xff0c;老外更喜欢侧边菜单。 如果我们使用一个activity来创建程序&#xff0c;来用占位符管理多个fragment切换&…

网络连接之队头阻塞!!!

一、什么是队头阻塞 队头阻塞&#xff0c;在网络模型中简单理解就是&#xff0c;对于队列型的请求模型&#xff0c;如HTTP的请求-响应模型、TCP的ACK确认机制&#xff0c;都依赖得到一个具体的响应包&#xff0c;如果收不到这个响应包&#xff0c;那下一个请求就不能发&#x…

如何高效安全的开展HPC数据传输,保护数据安全?

高性能计算&#xff08;HPC&#xff09;在多个行业和领域中都有广泛的应用&#xff0c;像科学研究机构、芯片IC设计企业、金融、生物制药、能源、航天航空等。HPC&#xff08;高性能计算&#xff09;环境中的数据传输是一个关键环节&#xff0c;它涉及到将数据快速、安全地在不…

hive的表操作

常用的hive命令 切换数据库use test;查询表的建表信息show create table 数据库名称.表名;查看表的类型信息desc formatted 数据库名称.表名; 删除内部表 drop table 数据库名称.表名; 先启动hdfs &#xff0c;mysql &#xff0c; hiveservice2&#xff0c;beeline CREATE [EX…