GithubHelp home page GithubHelp logo

enum's Introduction

说明:http://t.csdn.cn/CG5Rb

作用

  1. 使用提供的ENUM宏定义enum后,提供函数,可以将enum转换为string,也可以通过string获取对应enum的值,定义和使用过程和直接使用enum关键字差不多。

  2. 提供3个函数,如果不是使用ENUM宏定义的enum无法调用。

    enum2Str()// enum转字符串

    str2Enum() // 字符串转enum,没有返回false

    getEnumName()// 获取enum类的名字

ENUM接口解释

ENUM(Arg1, Arg2, Arg3...)

Arg1: 定义的enum的名称。

Arg2:enum类的类型。

Arg3...:enum类的成员,个数最多为63个。

演示

#include"ENUM/ENUM.hpp"

#include<cstring>

#include<iostream>


// VC++需要选择“配置属性”>“C/C++”>“命令行”属性页。

// 修改“附加选项”属性以包含 /experimental:preprocessor,然后选择“确定”


ENUM(Enum1, char, (idleDown), idle, (idleUp, 2), (idleRight, -3), (idleLeft, 10), IDLE);


structExample {

    ENUM(Enum2, char, (enum3), (enum4));

};


classExampleClass {

    ENUM(Enum3, char, (enum5), (enum6));

};


intexample()

{

    usingnamespace 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;

    return0;

}

原理

使用宏和和编译期计算功能,在编译期的时候对参数进行展开和计算,自动生成对应的函数,尽量减少运行时的时间和空间复杂度。

CPP版本

运行测试版本 >= C++11。

使用成本分析

| 代价 | 运行和使用 | 待改进 |

| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- |

| 1.增加编译时间,生成的目标文件会增大(可忽略不计)。<br/>2.宏可能会给调试增加难度。<br/>3. 如果两个不同的枚举量的hash相同,编译会报错(简单测试过63个参数,没遇到)。 | 1.运行时,字符串转enum时间复杂度和空间复杂度为n,和字符串的长度有关。enum转字符时间和空间复杂度为常数。<br/>2.线程安全。<br/>3.用ENUM定义枚举类型和直接使用enum差不多,用ENUM定义能得到普通的枚举类型同时,也会得到相应的函数。<br/>4.支持自定义顺序。 | 1.因为是使用宏来展开的,需要自己编写展开的宏,现在支持的最大枚举参数为63个。 |

代码分析

宏展开

  1. 首先需要需要获取传进宏的枚举的参数的个数的数量。

    /************************** 获取宏的参数个数 ********************/
    
    #defineARG_N(...) \
    
        ARG_N_(0, ##__VA_ARGS__, ARG_N_RESQ)
    
    
    #defineARG_N_(...) \
    
        ARG_N_M(__VA_ARGS__)
    
    
    #defineARG_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
    
    
  2. 展开枚举的参数的宏,宏不支持递归,没想到优雅展开宏参数的写法,直接手动编写。

    #defineEXPAND_ARG0()
    
    #defineEXPAND_ARG1(MACRO, x) MACRO(x, 0)
    
    #defineEXPAND_ARG2(MACRO, x, ...) MACRO(x, 1) EXPAND_ARG1(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG3(MACRO, x, ...) MACRO(x, 2) EXPAND_ARG2(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG4(MACRO, x, ...) MACRO(x, 3) EXPAND_ARG3(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG5(MACRO, x, ...) MACRO(x, 4) EXPAND_ARG4(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG6(MACRO, x, ...) MACRO(x, 5) EXPAND_ARG5(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG7(MACRO, x, ...) MACRO(x, 6) EXPAND_ARG6(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG8(MACRO, x, ...) MACRO(x, 7) EXPAND_ARG7(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG9(MACRO, x, ...) MACRO(x, 8) EXPAND_ARG8(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG10(MACRO, x, ...) MACRO(x, 9) EXPAND_ARG9(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG11(MACRO, x, ...) MACRO(x, 10) EXPAND_ARG10(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG12(MACRO, x, ...) MACRO(x, 11) EXPAND_ARG11(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG13(MACRO, x, ...) MACRO(x, 12) EXPAND_ARG12(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG14(MACRO, x, ...) MACRO(x, 13) EXPAND_ARG13(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG15(MACRO, x, ...) MACRO(x, 14) EXPAND_ARG14(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG16(MACRO, x, ...) MACRO(x, 15) EXPAND_ARG15(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG17(MACRO, x, ...) MACRO(x, 16) EXPAND_ARG16(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG18(MACRO, x, ...) MACRO(x, 17) EXPAND_ARG17(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG19(MACRO, x, ...) MACRO(x, 18) EXPAND_ARG18(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG20(MACRO, x, ...) MACRO(x, 19) EXPAND_ARG19(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG21(MACRO, x, ...) MACRO(x, 20) EXPAND_ARG20(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG22(MACRO, x, ...) MACRO(x, 21) EXPAND_ARG21(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG23(MACRO, x, ...) MACRO(x, 22) EXPAND_ARG22(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG24(MACRO, x, ...) MACRO(x, 23) EXPAND_ARG23(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG25(MACRO, x, ...) MACRO(x, 24) EXPAND_ARG24(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG26(MACRO, x, ...) MACRO(x, 25) EXPAND_ARG25(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG27(MACRO, x, ...) MACRO(x, 26) EXPAND_ARG26(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG28(MACRO, x, ...) MACRO(x, 27) EXPAND_ARG27(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG29(MACRO, x, ...) MACRO(x, 28) EXPAND_ARG28(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG30(MACRO, x, ...) MACRO(x, 29) EXPAND_ARG29(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG31(MACRO, x, ...) MACRO(x, 30) EXPAND_ARG30(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG32(MACRO, x, ...) MACRO(x, 31) EXPAND_ARG31(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG33(MACRO, x, ...) MACRO(x, 32) EXPAND_ARG32(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG34(MACRO, x, ...) MACRO(x, 33) EXPAND_ARG33(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG35(MACRO, x, ...) MACRO(x, 34) EXPAND_ARG34(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG36(MACRO, x, ...) MACRO(x, 35) EXPAND_ARG35(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG37(MACRO, x, ...) MACRO(x, 36) EXPAND_ARG36(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG38(MACRO, x, ...) MACRO(x, 37) EXPAND_ARG37(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG39(MACRO, x, ...) MACRO(x, 38) EXPAND_ARG38(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG40(MACRO, x, ...) MACRO(x, 39) EXPAND_ARG39(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG41(MACRO, x, ...) MACRO(x, 40) EXPAND_ARG40(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG42(MACRO, x, ...) MACRO(x, 41) EXPAND_ARG41(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG43(MACRO, x, ...) MACRO(x, 42) EXPAND_ARG42(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG44(MACRO, x, ...) MACRO(x, 43) EXPAND_ARG43(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG45(MACRO, x, ...) MACRO(x, 44) EXPAND_ARG44(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG46(MACRO, x, ...) MACRO(x, 45) EXPAND_ARG45(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG47(MACRO, x, ...) MACRO(x, 46) EXPAND_ARG46(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG48(MACRO, x, ...) MACRO(x, 47) EXPAND_ARG47(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG49(MACRO, x, ...) MACRO(x, 48) EXPAND_ARG48(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG50(MACRO, x, ...) MACRO(x, 49) EXPAND_ARG49(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG51(MACRO, x, ...) MACRO(x, 50) EXPAND_ARG50(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG52(MACRO, x, ...) MACRO(x, 51) EXPAND_ARG51(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG53(MACRO, x, ...) MACRO(x, 52) EXPAND_ARG52(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG54(MACRO, x, ...) MACRO(x, 53) EXPAND_ARG53(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG55(MACRO, x, ...) MACRO(x, 54) EXPAND_ARG54(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG56(MACRO, x, ...) MACRO(x, 55) EXPAND_ARG55(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG57(MACRO, x, ...) MACRO(x, 56) EXPAND_ARG56(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG58(MACRO, x, ...) MACRO(x, 57) EXPAND_ARG57(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG59(MACRO, x, ...) MACRO(x, 58) EXPAND_ARG58(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG60(MACRO, x, ...) MACRO(x, 59) EXPAND_ARG59(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG61(MACRO, x, ...) MACRO(x, 60) EXPAND_ARG60(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG62(MACRO, x, ...) MACRO(x, 61) EXPAND_ARG61(MACRO, __VA_ARGS__)
    
    #defineEXPAND_ARG63(MACRO, x, ...) MACRO(x, 62) EXPAND_ARG62(MACRO, __VA_ARGS__)
    
    
    
  3. 使用上边写的宏,根据宏传入的参数个数获取对应的展开参数的宏

    #defineARG_CONCAT_(l, r) l##r
    
    #defineARG_CONCAT(l, r) ARG_CONCAT_(l, r)
    
    
    #defineEXPAND(MACRO, ...) ARG_CONCAT(EXPAND_ARG, ARG_N(__VA_ARGS__))(MACRO, __VA_ARGS__)
    
    

计算字符串的hash值

在编译期将字符串转换为hash值,并且在运行将字符串转变为hash值去匹配。

/************************************计算HASH值********************************************/

/************************************计算HASH值********************************************/

#pragmaonce


// 返回字符串长度

#define STR_SIZE(STR)(sizeof(STR)-1)

// Hash计算公式

#define COMPUTE(SEED,STR,N)((unsigned int)(SEED ^STR[N]+0x9e3779b9+(SEED <<6)+(SEED >>2)))

// 字符串计算hash值

constexprunsignedintcompute(unsignedint&&seed, constchar*val, intNUM)

{

    return NUM > 0 ? compute(COMPUTE(seed, val, NUM - 1), val, NUM - 1) : seed;

}

ENUM宏

自动生成转换代码的ENUM宏。enum转字符串,展开时用E2S宏替换,返回字符串。字符串转enum时,展开是用S2E替换,将传入字符串转换为hash,然后匹配编译期生成的hash值,匹配到返回true。

#pragmaonce

#include"PP.hpp"

#include"computeHash.hpp"

#include"expandMacro.h"

#include<string>


// 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)): {      \

        returnPP_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_NAMEEnum)                                      \

    {                                                                                \

        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)                    \

    {                                                                                \

        returnstr2Enum(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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.