C++实现反射机制(一)

NET下的很多技术都是基于反射机制来实现的,反射让.NET平台下的语言变得得心应手。最简单的,比如枚举类型,我们我可以很容易的获得一个枚举变量的数值以及其名称字符串。

可是,在C++中,枚举变量本质上和一个整形变量没有区别,我们很难获取一个枚举变量的名称字符串。

其实在C++中,我们可以通过宏来实现类似反射的机制。

接下来,我想总结一下如何在C++中实现一个类似于C#枚举类型的方法。

__VA_ARGS__
使用__VA_ARGS__,我们可以定义带可变参数的宏,举个例子:

#define MY_PRINTF(…) printf(__VA_ARGS__)

这样我们写

MY_PRINTF("hello, %s”, "world");

就等价于

printf("hello, %s”, "world");


 

宏的"##"符号

"##"符号的作用是在可变参数的个数为0时,消除参数前面的逗号:

#define MY_PRINTF(fs, …) printf(fs, ##__VA_ARGS__)

我们这样调用:

MY_PRINTF(“Hello, World”);

等价于

printf(“Hello, World”);

另外"##"符号还能够去掉括号,但是我现在还不是很明白,为什么能够做到这一点:

 

#define ENUM_COTENTS(...) __VA_ARGS__ 
#define ENUM_CONTENT_REMOVE_PARENTHESIS(a) ENUM_COTENTS##a 
#define DEFINE_ENUM(name) enum name { ENUM_CONTENT_REMOVE_PARENTHESIS(ENUM_LIST) }; 
#define ENUM_LIST (Sunday=1,Monday=2) 
DEFINE_ENUM(WeekDay)

宏的"#"符号

"#"符号的作用是“字符化”代码:

#define MY_STRINGLIZED_MACRO(str) #str
int helloWorld = 0;
printf(MY_STRINGLIZED_MACRO(helloWorld)); // output: helloWorld

利用C++宏实现简单的.NET枚举类型

我做了一个简单的用例,最终示例代码如下:

#include "DefineEnum.h" 
#define ENUM_LIST                                   \ 
        ENUM_NAME(Sunday     ENUM_VALUE(10)),       \ 
        ENUM_NAME(Monday     ENUM_VALUE(Sunday+1)),     \ 
        ENUM_NAME(Tuesday    ENUM_VALUE(123)),      \ 
        ENUM_NAME(Wednesday  ENUM_VALUE(10)) ,      \ 
        ENUM_NAME(Thursday   ENUM_VALUE(7)),        \ 
        ENUM_NAME(Friday     ENUM_VALUE(8)),        \ 
        ENUM_NAME(Saturday   ENUM_VALUE(12)) 
  
DEFINE_ENUM(WeekDay); 
  
#include "RegisterEnum.h" 
REGISTER_ENUM(WeekDay); 
  
  
int main() 
{ 
    printf("%s is %d.", EnumHelper<WeekDay>::ToString(Monday), Monday); 
    getchar(); 
    return 0; 
}
DefineEnum.h
#undef ENUM_LIST 
  
#undef ENUM_NAME 
#define ENUM_NAME(...)  __VA_ARGS__ 
  
  
#undef ENUM_VALUE 
#define ENUM_VALUE(val) = val 
  
#define ENUM_COTENTS(...)  __VA_ARGS__ 
  
#define DEFINE_ENUM(name)  enum name { ENUM_COTENTS(ENUM_LIST) };
RegisterEnum.h
#include "ReflectEnum.h" 
  
#undef ENUM_VALUE 
#define ENUM_VALUE(val) 
  
#define REGISTER_ENUM(name)  REFLECT_ENUM(name, ENUM_LIST )
ReflectEnum.h
#ifndef REFLECT_ENUM_INCLUDE_GUARD 
  
#include <string> 
#include <cstring> 
#include <stdexcept> // for runtime_error 
  
#endif 
  
template <typename Enum_T> class EnumHelper 
{ 
public: 
    static const char * ToString(Enum_T e) 
    { 
        for(int i = 0; i < _countof(EnumHelper<Enum_T>::s_allEnums); i++) 
        { 
            if( s_allEnums[i] == e) 
                return s_allEnumNames[i]; 
        } 
        return NULL; 
    } 
  
private: 
    static const char * s_typeName; 
    static Enum_T s_allEnums[]; 
    static char s_singleEnumStr[]; 
    static const char * s_allEnumNames[]; 
  
    static void SplitEnumDefString() 
    { 
        char * p = s_singleEnumStr; 
        while( isspace(*p) ) p++; 
        for(int i = 0; i < _countof(EnumHelper<Enum_T>::s_allEnums); i++) 
        { 
            s_allEnumNames[i] = p; 
            while( *p == '_' || isdigit(*p) || isalpha(*p) ) p++; 
            bool meet_comma = ( *p == ',' ); 
            *p++ = '\0'; 
            if( !meet_comma ) 
            { 
                while( *p && *p != ',') p++; 
                if( *p ) p++; 
            } 
            while( *p && isspace(*p) ) p++; 
        } 
    } 
}; 
  
#define TO_ENUM_ITEM(...)  __VA_ARGS__ 
#define STRINGIZE(...)  #__VA_ARGS__ 
  
#define REFLECT_ENUM(enum_type_name, enum_list)                                                                         \ 
template<> enum_type_name EnumHelper<enum_type_name>::s_allEnums[] =                                                    \ 
{                                                                                                                       \ 
    TO_ENUM_ITEM(enum_list)                                                                                             \ 
};                                                                                                                      \ 
template<> const char* EnumHelper<enum_type_name>::s_allEnumNames[_countof(EnumHelper<enum_type_name>::s_allEnums)];  \ 
template<> char EnumHelper<enum_type_name>::s_singleEnumStr[] = STRINGIZE(enum_list) ;                                  \ 
template<> const char * EnumHelper<enum_type_name>::s_typeName = (EnumHelper<enum_type_name>::SplitEnumDefString(), #enum_type_name);





你可能感兴趣的:(C++,.net,list,String,include,output)