使用提供的ENUM宏定义enum后,提供函数,可以将enum转换为string,也可以通过string获取对应enum的值,定义和使用过程和直接使用enum关键字差不多。
提供3个函数,如果不是使用ENUM宏定义的enum无法调用。
enum2Str()// enum转字符串
str2Enum() // 字符串转enum,没有返回false
getEnumName()// 获取enum类的名字
ENUM(Arg1, Arg2, Arg3…)
Arg1: 定义的enum的名称。
Arg2:enum类的类型。
Arg3…:enum类的成员,个数最多为63个。
#include "ENUM/ENUM.hpp"
#include
#include
// VC++需要选择“配置属性”>“C/C++”>“命令行”属性页。
// 修改“附加选项”属性以包含 /experimental:preprocessor,然后选择“确定”
ENUM(Enum1, char, (idleDown), idle, (idleUp, 2), (idleRight, -3), (idleLeft, 10), IDLE);
struct Example {
ENUM(Enum2, char, (enum3), (enum4));
};
class ExampleClass {
ENUM(Enum3, char, (enum5), (enum6));
};
int example()
{
using namespace std;
Enum1 x = Enum1::idleRight; // idleRight = -3
char str1[] = "str";
cout << std::boolalpha << str2Enum(str1, strlen(str1), x) << endl; // cout: false
cout << x << endl; // cout: -3
cout << enum2Str(x) << endl; // cout: idleRight
cout << "------------------------" << endl;
string str2 = "idleDown"; // 0
cout << std::boolalpha << str2Enum(str2, x) << endl; // cout: true
cout << x << endl; // cout: 0
cout << enum2Str(x) << endl; // cout: idleDown
cout << "name: " << getEnumName(x) << endl; // cout: name: Enum1
cout << "------------------------" << endl;
Example::Enum2 xx = Example::Enum2::enum3;
char str3[] = "str";
cout << std::boolalpha << Example::str2Enum(str3, strlen(str3), xx) << endl; // cout: false
cout << xx << endl; // cout: 0
cout << Example::enum2Str(xx) << endl; // cout: enum3
cout << "------------------------" << endl;
string str4 = "enum4"; // 1
cout << std::boolalpha << Example::str2Enum(str4, xx) << endl; // cout: true
cout << xx << endl; // cout: 1
cout << Example::enum2Str(xx) << endl; // cout: enum4
cout << "name: " << Example::getEnumName(xx) << endl; // cout: name: Enum2
cout << "------------------------" << endl;
return 0;
}
使用宏和和编译期计算功能,在编译期的时候对参数进行展开和计算,自动生成对应的函数,尽量减少运行时的时间和空间复杂度。
运行测试版本 >= C++11。
代价 | 运行和使用 | 待改进 |
---|---|---|
1.增加编译时间,生成的目标文件会增大(可忽略不计)。 2.宏可能会给调试增加难度。 3. 如果两个不同的枚举量的hash相同,编译会报错(简单测试过63个参数,没遇到)。 |
1.运行时,字符串转enum时间复杂度和空间复杂度为n,和字符串的长度有关。enum转字符时间和空间复杂度为常数。 2.线程安全。 3.用ENUM定义枚举类型和直接使用enum差不多,用ENUM定义能得到普通的枚举类型同时,也会得到相应的函数。 4.支持自定义顺序。 |
1.因为是使用宏来展开的,需要自己编写展开的宏,现在支持的最大枚举参数为63个。 |
首先需要需要获取传进宏的枚举的参数的个数的数量。
/************************** 获取宏的参数个数 ********************/
#define ARG_N(...) \
ARG_N_(0, ##__VA_ARGS__, ARG_N_RESQ)
#define ARG_N_(...) \
ARG_N_M(__VA_ARGS__)
#define ARG_N_M( \
_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
_11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
_21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
_31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
_41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
_51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
_61, _62, _63, N, ...) N
#define ARG_N_RESQ \
63, 62, 61, 60, \
59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \
49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \
39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \
29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \
19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \
9, 8, 7, 6, 5, 4, 3, 2, 1, 0
展开枚举的参数的宏,宏不支持递归,没想到优雅展开宏参数的写法,直接手动编写。
#define EXPAND_ARG0()
#define EXPAND_ARG1(MACRO, x) MACRO(x, 0)
#define EXPAND_ARG2(MACRO, x, ...) MACRO(x, 1) EXPAND_ARG1(MACRO, __VA_ARGS__)
#define EXPAND_ARG3(MACRO, x, ...) MACRO(x, 2) EXPAND_ARG2(MACRO, __VA_ARGS__)
#define EXPAND_ARG4(MACRO, x, ...) MACRO(x, 3) EXPAND_ARG3(MACRO, __VA_ARGS__)
#define EXPAND_ARG5(MACRO, x, ...) MACRO(x, 4) EXPAND_ARG4(MACRO, __VA_ARGS__)
#define EXPAND_ARG6(MACRO, x, ...) MACRO(x, 5) EXPAND_ARG5(MACRO, __VA_ARGS__)
#define EXPAND_ARG7(MACRO, x, ...) MACRO(x, 6) EXPAND_ARG6(MACRO, __VA_ARGS__)
#define EXPAND_ARG8(MACRO, x, ...) MACRO(x, 7) EXPAND_ARG7(MACRO, __VA_ARGS__)
#define EXPAND_ARG9(MACRO, x, ...) MACRO(x, 8) EXPAND_ARG8(MACRO, __VA_ARGS__)
#define EXPAND_ARG10(MACRO, x, ...) MACRO(x, 9) EXPAND_ARG9(MACRO, __VA_ARGS__)
#define EXPAND_ARG11(MACRO, x, ...) MACRO(x, 10) EXPAND_ARG10(MACRO, __VA_ARGS__)
#define EXPAND_ARG12(MACRO, x, ...) MACRO(x, 11) EXPAND_ARG11(MACRO, __VA_ARGS__)
#define EXPAND_ARG13(MACRO, x, ...) MACRO(x, 12) EXPAND_ARG12(MACRO, __VA_ARGS__)
#define EXPAND_ARG14(MACRO, x, ...) MACRO(x, 13) EXPAND_ARG13(MACRO, __VA_ARGS__)
#define EXPAND_ARG15(MACRO, x, ...) MACRO(x, 14) EXPAND_ARG14(MACRO, __VA_ARGS__)
#define EXPAND_ARG16(MACRO, x, ...) MACRO(x, 15) EXPAND_ARG15(MACRO, __VA_ARGS__)
#define EXPAND_ARG17(MACRO, x, ...) MACRO(x, 16) EXPAND_ARG16(MACRO, __VA_ARGS__)
#define EXPAND_ARG18(MACRO, x, ...) MACRO(x, 17) EXPAND_ARG17(MACRO, __VA_ARGS__)
#define EXPAND_ARG19(MACRO, x, ...) MACRO(x, 18) EXPAND_ARG18(MACRO, __VA_ARGS__)
#define EXPAND_ARG20(MACRO, x, ...) MACRO(x, 19) EXPAND_ARG19(MACRO, __VA_ARGS__)
#define EXPAND_ARG21(MACRO, x, ...) MACRO(x, 20) EXPAND_ARG20(MACRO, __VA_ARGS__)
#define EXPAND_ARG22(MACRO, x, ...) MACRO(x, 21) EXPAND_ARG21(MACRO, __VA_ARGS__)
#define EXPAND_ARG23(MACRO, x, ...) MACRO(x, 22) EXPAND_ARG22(MACRO, __VA_ARGS__)
#define EXPAND_ARG24(MACRO, x, ...) MACRO(x, 23) EXPAND_ARG23(MACRO, __VA_ARGS__)
#define EXPAND_ARG25(MACRO, x, ...) MACRO(x, 24) EXPAND_ARG24(MACRO, __VA_ARGS__)
#define EXPAND_ARG26(MACRO, x, ...) MACRO(x, 25) EXPAND_ARG25(MACRO, __VA_ARGS__)
#define EXPAND_ARG27(MACRO, x, ...) MACRO(x, 26) EXPAND_ARG26(MACRO, __VA_ARGS__)
#define EXPAND_ARG28(MACRO, x, ...) MACRO(x, 27) EXPAND_ARG27(MACRO, __VA_ARGS__)
#define EXPAND_ARG29(MACRO, x, ...) MACRO(x, 28) EXPAND_ARG28(MACRO, __VA_ARGS__)
#define EXPAND_ARG30(MACRO, x, ...) MACRO(x, 29) EXPAND_ARG29(MACRO, __VA_ARGS__)
#define EXPAND_ARG31(MACRO, x, ...) MACRO(x, 30) EXPAND_ARG30(MACRO, __VA_ARGS__)
#define EXPAND_ARG32(MACRO, x, ...) MACRO(x, 31) EXPAND_ARG31(MACRO, __VA_ARGS__)
#define EXPAND_ARG33(MACRO, x, ...) MACRO(x, 32) EXPAND_ARG32(MACRO, __VA_ARGS__)
#define EXPAND_ARG34(MACRO, x, ...) MACRO(x, 33) EXPAND_ARG33(MACRO, __VA_ARGS__)
#define EXPAND_ARG35(MACRO, x, ...) MACRO(x, 34) EXPAND_ARG34(MACRO, __VA_ARGS__)
#define EXPAND_ARG36(MACRO, x, ...) MACRO(x, 35) EXPAND_ARG35(MACRO, __VA_ARGS__)
#define EXPAND_ARG37(MACRO, x, ...) MACRO(x, 36) EXPAND_ARG36(MACRO, __VA_ARGS__)
#define EXPAND_ARG38(MACRO, x, ...) MACRO(x, 37) EXPAND_ARG37(MACRO, __VA_ARGS__)
#define EXPAND_ARG39(MACRO, x, ...) MACRO(x, 38) EXPAND_ARG38(MACRO, __VA_ARGS__)
#define EXPAND_ARG40(MACRO, x, ...) MACRO(x, 39) EXPAND_ARG39(MACRO, __VA_ARGS__)
#define EXPAND_ARG41(MACRO, x, ...) MACRO(x, 40) EXPAND_ARG40(MACRO, __VA_ARGS__)
#define EXPAND_ARG42(MACRO, x, ...) MACRO(x, 41) EXPAND_ARG41(MACRO, __VA_ARGS__)
#define EXPAND_ARG43(MACRO, x, ...) MACRO(x, 42) EXPAND_ARG42(MACRO, __VA_ARGS__)
#define EXPAND_ARG44(MACRO, x, ...) MACRO(x, 43) EXPAND_ARG43(MACRO, __VA_ARGS__)
#define EXPAND_ARG45(MACRO, x, ...) MACRO(x, 44) EXPAND_ARG44(MACRO, __VA_ARGS__)
#define EXPAND_ARG46(MACRO, x, ...) MACRO(x, 45) EXPAND_ARG45(MACRO, __VA_ARGS__)
#define EXPAND_ARG47(MACRO, x, ...) MACRO(x, 46) EXPAND_ARG46(MACRO, __VA_ARGS__)
#define EXPAND_ARG48(MACRO, x, ...) MACRO(x, 47) EXPAND_ARG47(MACRO, __VA_ARGS__)
#define EXPAND_ARG49(MACRO, x, ...) MACRO(x, 48) EXPAND_ARG48(MACRO, __VA_ARGS__)
#define EXPAND_ARG50(MACRO, x, ...) MACRO(x, 49) EXPAND_ARG49(MACRO, __VA_ARGS__)
#define EXPAND_ARG51(MACRO, x, ...) MACRO(x, 50) EXPAND_ARG50(MACRO, __VA_ARGS__)
#define EXPAND_ARG52(MACRO, x, ...) MACRO(x, 51) EXPAND_ARG51(MACRO, __VA_ARGS__)
#define EXPAND_ARG53(MACRO, x, ...) MACRO(x, 52) EXPAND_ARG52(MACRO, __VA_ARGS__)
#define EXPAND_ARG54(MACRO, x, ...) MACRO(x, 53) EXPAND_ARG53(MACRO, __VA_ARGS__)
#define EXPAND_ARG55(MACRO, x, ...) MACRO(x, 54) EXPAND_ARG54(MACRO, __VA_ARGS__)
#define EXPAND_ARG56(MACRO, x, ...) MACRO(x, 55) EXPAND_ARG55(MACRO, __VA_ARGS__)
#define EXPAND_ARG57(MACRO, x, ...) MACRO(x, 56) EXPAND_ARG56(MACRO, __VA_ARGS__)
#define EXPAND_ARG58(MACRO, x, ...) MACRO(x, 57) EXPAND_ARG57(MACRO, __VA_ARGS__)
#define EXPAND_ARG59(MACRO, x, ...) MACRO(x, 58) EXPAND_ARG58(MACRO, __VA_ARGS__)
#define EXPAND_ARG60(MACRO, x, ...) MACRO(x, 59) EXPAND_ARG59(MACRO, __VA_ARGS__)
#define EXPAND_ARG61(MACRO, x, ...) MACRO(x, 60) EXPAND_ARG60(MACRO, __VA_ARGS__)
#define EXPAND_ARG62(MACRO, x, ...) MACRO(x, 61) EXPAND_ARG61(MACRO, __VA_ARGS__)
#define EXPAND_ARG63(MACRO, x, ...) MACRO(x, 62) EXPAND_ARG62(MACRO, __VA_ARGS__)
使用上边写的宏,根据宏传入的参数个数获取对应的展开参数的宏
#define ARG_CONCAT_(l, r) l##r
#define ARG_CONCAT(l, r) ARG_CONCAT_(l, r)
#define EXPAND(MACRO, ...) ARG_CONCAT(EXPAND_ARG, ARG_N(__VA_ARGS__))(MACRO, __VA_ARGS__)
在编译期将字符串转换为hash值,并且在运行将字符串转变为hash值去匹配。
/************************************计算HASH值********************************************/
/************************************计算HASH值********************************************/
#pragma once
// 返回字符串长度
#define STR_SIZE(STR) (sizeof(STR) - 1)
// Hash计算公式
#define COMPUTE(SEED, STR, N) ((unsigned int)(SEED ^ STR[N] + 0x9e3779b9 + (SEED << 6) + (SEED >> 2)))
// 字符串计算hash值
constexpr unsigned int compute(unsigned int&& seed, const char* val, int NUM)
{
return NUM > 0 ? compute(COMPUTE(seed, val, NUM - 1), val, NUM - 1) : seed;
}
自动生成转换代码的ENUM宏。enum转字符串,展开时用E2S宏替换,返回字符串。字符串转enum时,展开是用S2E替换,将传入字符串转换为hash,然后匹配编译期生成的hash值,匹配到返回true。
#pragma once
#include "PP.hpp"
#include "computeHash.hpp"
#include "expandMacro.h"
#include
// GCC 的宏不支持和‘(’连接, VC通过
// 选择“配置属性”>“C/C++”>“命令行”属性页。
// 修改“附加选项”属性以包含 /experimental:preprocessor,然后选择“确定”
#define PARAM_ENUM_1(X) X,
#define PARAM_ENUM_2(X, Y) X = Y,
#define PARAM_ENUM_END_1(X) X
#define PARAM_ENUM_END_2(X, Y) X = Y
// 元组处理
#define CALL_FUN(FUN, X) FUN X
#define COUNT_BRACKET(...) ARG_N(__VA_ARGS__)
#define PP_BRACKET(...) __VA_ARGS__
#define PP_IF(FREE, THEN, ELSE) ARG_CONCAT(PP_IF_, PP_BOOL(FREE))(THEN, ELSE)
#define PP_IF_0(THEN, ELSE) ELSE
#define PP_IF_1(THEN, ELSE) THEN
#define PARAM_ENUM_IMPL_1(X, NUM) PP_IF(NUM, \
(CALL_FUN(ARG_CONCAT(PARAM_ENUM_, CALL_FUN(COUNT_BRACKET, X)), X)), \
(CALL_FUN(ARG_CONCAT(PARAM_ENUM_END_, CALL_FUN(COUNT_BRACKET, X)), X)))
#define PARAM_ENUM_IMPL_2(X, NUM) PP_IF(NUM, (PARAM_ENUM_1(X)), (PARAM_ENUM_END_1(X)))
#define PARAM_ENUM_IMPL(X, NUM) PP_IF(PP_IS_PARENS(X), (PARAM_ENUM_IMPL_1(X, NUM)), (PARAM_ENUM_IMPL_2(X, NUM)))
#define PARAM_ENUM(X, NUM) CALL_FUN(PP_BRACKET, CALL_FUN(PP_BRACKET, PARAM_ENUM_IMPL(X, NUM)))
#define GET_PAR_1(X) X
#define GET_PAR_2(X, Y) X
#define GET_PAR(X) CALL_FUN(ARG_CONCAT(GET_PAR_, CALL_FUN(COUNT_BRACKET, X)), X)
#define TO_STR_(X) #X
#define TO_STR(X) TO_STR_(X)
#define TUPLE_STR(X) TO_STR(GET_PAR(X))
#define E2S_(X, NUM) \
case (PP_IF(PP_IS_PARENS(X), GET_PAR(X), X)): { \
return PP_IF(PP_IS_PARENS(X), TUPLE_STR(X), #X); \
}
#define S2E_(X, NUM) \
case (compute(0, PP_IF(PP_IS_PARENS(X), TUPLE_STR(X), #X), STR_SIZE(PP_IF(PP_IS_PARENS(X), TUPLE_STR(X), #X)))): { \
Enum = PP_IF(PP_IS_PARENS(X), GET_PAR(X), X); \
ret = true; \
break; \
}
#define ENUM(ENUM_NAME, TYPE, ...) \
enum ENUM_NAME : TYPE { EXPAND(PARAM_ENUM, __VA_ARGS__) }; \
static const char* enum2Str(ENUM_NAME Enum) \
{ \
switch (Enum) { \
EXPAND(E2S_, __VA_ARGS__) \
default: { \
break; \
} \
} \
return nullptr; \
} \
static bool str2Enum(const char* str, const unsigned int& size, ENUM_NAME& Enum) \
{ \
bool ret = false; \
unsigned int s = compute(0, str, size); \
switch (s) { \
EXPAND(S2E_, __VA_ARGS__) \
default: { \
break; \
} \
} \
return ret; \
} \
static bool str2Enum(const std::string& str, ENUM_NAME& Enum) \
{ \
return str2Enum(str.c_str(), str.length(), Enum); \
} \
static const char* getEnumName(ENUM_NAME& Enum) \
{ \
return #ENUM_NAME; \
}
github仓库地址
gitee仓库地址
《C++标准库(第二版)》
https://zhuanlan.zhihu.com/p/152354031