c++枚举字符串转换工具

为什么会需要这样一个枚举转字符串,字符串转枚举的工具?

在太多的工程中,我们可能都需要将一些枚举、整形标记打到日志中去,如果只打印数组,那也不行啊,出问题翻看日志,还得一个个查询,这时候我们该怎么办呢,写一堆if else,写一堆switch,挨个匹配字符,那只能说,小学生代码,能不能搞一个通用的转换呢?答案肯定是能的。

枚举字符串接口设计

在这里插入图片描述

代码实现

#include <string>
#include <algorithm>
#include <vector>

template<typename E>
class EnumStrings {
    
    
public:
	EnumStrings(std::initializer_list<std::pair<E, std::string> > list) {
    
    
		m_eValue = m_stringValue = list;
		std::sort(m_eValue.begin(), m_eValue.end(), CompareFirst);
		std::sort(m_stringValue.begin(), m_stringValue.end(), CompareSecond);
	}
	inline static std::string ToString(E value) {
    
    
		auto it = std::lower_bound(gSingleton.m_eValue.begin(),
            gSingleton.m_eValue.end(), std::make_pair(value, std::string()), CompareFirst);
		if(it == gSingleton.m_eValue.end() || it->first != value) {
    
    
			assert(false);
			return std::string();
		}
		return it->second;
	}
	inline static E FromString(const std::string& string, E fallback) {
    
    
		auto it = std::lower_bound(gSingleton.m_stringValue.begin(),
            gSingleton.m_stringValue.end(), std::make_pair((E) 0, string), CompareSecond);
		if(it == gSingleton.m_stringValue.end() || it->second != string)
			return fallback;
		return it->first;
	}
private:
	static const EnumStrings gSingleton;

private:
	std::vector<std::pair<E, std::string>> m_eValue; 
    std::vector<std::pair<E, std::string>> m_stringValue;
private:
	inline static bool CompareFirst(const std::pair<E, std::string>& a, const std::pair<E, std::string>& b) {
    
    
        return (a.first < b.first); }
	inline static bool CompareSecond(const std::pair<E, std::string>& a, const std::pair<E, std::string>& b) {
    
    
        return (a.second < b.second); }
};

template<typename E>
inline std::string EnumToString(E value) {
    
     return EnumStrings<E>::ToString(value); }
template<typename E>
inline E StringToEnum(const std::string& string, E fallback) {
    
     return EnumStrings<E>::FromString(string, fallback); }

#define ENUMSTRINGS(E) template<> const EnumStrings<E> EnumStrings<E>::gSingleton
  1. 思维导图概括在这里插入图片描述
  2. 数据的存储是由两个vector, 分别存以枚举排序、字符串排序后的值。
  3. 由于是模板类,可以将莫一种类型的模板实列声明为单列,那么该枚举类型在整个内存中只有一份,一种枚举 类型对应一份。
  4. 构造函数,使用列表初始化为参数,将枚举和字符串值一一传入、进行排序处理,并把值保存到vector中。
  5. toString 顾名思义就是用e查找对应的字符串,找不到自然返回空串
  6. formString 顾名思义,就是使用字符串找到对应的枚举。这里有个参数很有意思,fallback,他是什么意思呢,是退路,应变计划,说白了就是plant B 的意思。本身含义为找不到就返回fallback这个值。
  7. std::lower_bound 该函数是std algorithm里面的,含义大概就是将排好序的序列使用二分查找,返回第一个不小于目标元素的迭代器。就是说在指定范围类查找目标是,查找的结果 >= 目标值。
  8. 使用方法。
#include <iostream>
#include "EunmStrings.h"
enum ETest
{
    
    
    Login = 0,
    LoginOut,
    KikOut,
    Disconnected,
};

ENUMSTRINGS(ETest) = {
    
    
	{
    
    Login, "login"},
	{
    
    LoginOut, "login out"},
	{
    
    KikOut, "kikout"},
    {
    
    Disconnected, "disconnected"},
};
int main(int argc, char** argv)
{
    
    
    std::cout << "get string ETestf::Login = "
         << EnumToString(Login) << std::endl; // 模板自动推导得到响应的单例
    std::cout << "get enum login = " << (int)StringToEnum("login", Login) << std::endl;
    return 0;
}

输出

get string ETestf::Login = login
get enum login = 0

  1. 是不是可以比较大小的对象就可以转字符串呢?比如 int的类型的flag, string 类型的中英转换,毕竟一句英文字符和一句中文字符一一对应。

这仅仅是一篇源码分析的文章

  1. 这么有创造性的思想不是我等凡人能想到的,当初我也试过map转字符窜,数组转字符串,数组key对应value,这是很危险的,搞不好就来个数组越界,map的话,也可以使用两个,一个保存E,一个保存string, 也能达到相同的效果,可是我那么笨呀,想不到呀。
  2. 最最精华的都不是这些,最精华的思想就在于一个命名空间下只会有一个枚举,多了也编不过,符号重定义,使用一个枚举推导一个模板类实列,对应一个单例,调用接口函数直接由模板推导出不同类型枚举的单例,从而获取到真正的值,真的是巧妙。
template<typename E>
inline std::string EnumToString(E value) {
    
     return EnumStrings<E>::ToString(value); }
template<typename E>
inline E StringToEnum(const std::string& string, E fallback) {
    
     return EnumStrings<E>::FromString(string, fallback); }

#define ENUMSTRINGS(E) template<> const EnumStrings<E> EnumStrings<E>::gSingleton
  1. 项目中使用vector是为了一次排序,快速取出,大佬的思想还是挺先进的,假如我换为map,感觉也是可以的,就仅仅速度慢了些,也不会说慢很多,在那么大的工程离,几乎可以忽略不计,这个设计是有一个缺陷的,假如我的枚举重复了,得到结果会正确吗?map直接去重,vector保留,但查到的永远只是第一个大于的,另一个值永远读取不到。但这本身就是错误,所以使用的时候要特别小心。能不能设计了编译期间就能判断枚举重复呢?对模板特性还不是特别熟悉。等将来在考虑吧,头疼。
  2. 最后还是看看源码吧,它源于ssr项目src/common/EnumStrings.h 可以访问 githbub-ssr 目睹下大佬们的风采,总是充满了思想的味道。

猜你喜欢

转载自blog.csdn.net/qq_33944628/article/details/125881625