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

来源:互联网 发布:人工智能分析用户行为 编辑:程序博客网 时间:2024/05/16 03:00
NET下的很多技术都是基于反射机制来实现的,反射让.NET平台下的语言变得得心应手。最简单的,比如枚举类型,我们我可以很容易的获得一个枚举变量的数值以及其名称字符串。

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

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

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

[cpp] view plaincopy
  1. __VA_ARGS__  
  2. 使用__VA_ARGS__,我们可以定义带可变参数的宏,举个例子:  
  3.   
  4. #define MY_PRINTF(…) printf(__VA_ARGS__)  
  5.   
  6. 这样我们写  
  7.   
  8. MY_PRINTF("hello, %s”, "world");  
  9.   
  10. 就等价于  
  11.   
  12. printf("hello, %s”, "world");  


 

宏的"##"符号

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

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

我们这样调用:

MY_PRINTF(“Hello, World”);

等价于

printf(“Hello, World”);

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

 

[cpp] view plaincopy
  1. #define ENUM_COTENTS(...) __VA_ARGS__   
  2. #define ENUM_CONTENT_REMOVE_PARENTHESIS(a) ENUM_COTENTS##a   
  3. #define DEFINE_ENUM(name) enum name { ENUM_CONTENT_REMOVE_PARENTHESIS(ENUM_LIST) };   
  4. #define ENUM_LIST (Sunday=1,Monday=2)   
  5. DEFINE_ENUM(WeekDay)  

宏的"#"符号

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

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

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

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

[cpp] view plaincopy
  1. #include "DefineEnum.h"   
  2. #define ENUM_LIST                                   \   
  3.         ENUM_NAME(Sunday     ENUM_VALUE(10)),       \   
  4.         ENUM_NAME(Monday     ENUM_VALUE(Sunday+1)),     \   
  5.         ENUM_NAME(Tuesday    ENUM_VALUE(123)),      \   
  6.         ENUM_NAME(Wednesday  ENUM_VALUE(10)) ,      \   
  7.         ENUM_NAME(Thursday   ENUM_VALUE(7)),        \   
  8.         ENUM_NAME(Friday     ENUM_VALUE(8)),        \   
  9.         ENUM_NAME(Saturday   ENUM_VALUE(12))   
  10.     
  11. DEFINE_ENUM(WeekDay);   
  12.     
  13. #include "RegisterEnum.h"   
  14. REGISTER_ENUM(WeekDay);   
  15.     
  16.     
  17. int main()   
  18. {   
  19.     printf("%s is %d.", EnumHelper<WeekDay>::ToString(Monday), Monday);   
  20.     getchar();   
  21.     return 0;   
  22. }  
DefineEnum.h
[cpp] view plaincopy
  1. #undef ENUM_LIST   
  2.     
  3. #undef ENUM_NAME   
  4. #define ENUM_NAME(...)  __VA_ARGS__   
  5.     
  6.     
  7. #undef ENUM_VALUE   
  8. #define ENUM_VALUE(val) = val   
  9.     
  10. #define ENUM_COTENTS(...)  __VA_ARGS__   
  11.     
  12. #define DEFINE_ENUM(name)  enum name { ENUM_COTENTS(ENUM_LIST) };  
RegisterEnum.h
[cpp] view plaincopy
  1. #include "ReflectEnum.h"   
  2.     
  3. #undef ENUM_VALUE   
  4. #define ENUM_VALUE(val)   
  5.     
  6. #define REGISTER_ENUM(name)  REFLECT_ENUM(name, ENUM_LIST )  
ReflectEnum.h
[cpp] view plaincopy
  1. #ifndef REFLECT_ENUM_INCLUDE_GUARD   
  2.     
  3. #include <string>   
  4. #include <cstring>   
  5. #include <stdexcept> // for runtime_error   
  6.     
  7. #endif   
  8.     
  9. template <typename Enum_T> class EnumHelper   
  10. {   
  11. public:   
  12.     static const char * ToString(Enum_T e)   
  13.     {   
  14.         for(int i = 0; i < _countof(EnumHelper<Enum_T>::s_allEnums); i++)   
  15.         {   
  16.             if( s_allEnums[i] == e)   
  17.                 return s_allEnumNames[i];   
  18.         }   
  19.         return NULL;   
  20.     }   
  21.     
  22. private:   
  23.     static const char * s_typeName;   
  24.     static Enum_T s_allEnums[];   
  25.     static char s_singleEnumStr[];   
  26.     static const char * s_allEnumNames[];   
  27.     
  28.     static void SplitEnumDefString()   
  29.     {   
  30.         char * p = s_singleEnumStr;   
  31.         while( isspace(*p) ) p++;   
  32.         for(int i = 0; i < _countof(EnumHelper<Enum_T>::s_allEnums); i++)   
  33.         {   
  34.             s_allEnumNames[i] = p;   
  35.             while( *p == '_' || isdigit(*p) || isalpha(*p) ) p++;   
  36.             bool meet_comma = ( *p == ',' );   
  37.             *p++ = '\0';   
  38.             if( !meet_comma )   
  39.             {   
  40.                 while( *p && *p != ',') p++;   
  41.                 if( *p ) p++;   
  42.             }   
  43.             while( *p && isspace(*p) ) p++;   
  44.         }   
  45.     }   
  46. };   
  47.     
  48. #define TO_ENUM_ITEM(...)  __VA_ARGS__   
  49. #define STRINGIZE(...)  #__VA_ARGS__   
  50.     
  51. #define REFLECT_ENUM(enum_type_name, enum_list)                                                                         \   
  52. template<> enum_type_name EnumHelper<enum_type_name>::s_allEnums[] =                                                    \   
  53. {                                                                                                                       \   
  54.     TO_ENUM_ITEM(enum_list)                                                                                             \   
  55. };                                                                                                                      \   
  56. template<> const char* EnumHelper<enum_type_name>::s_allEnumNames[_countof(EnumHelper<enum_type_name>::s_allEnums)];  \   
  57. template<> char EnumHelper<enum_type_name>::s_singleEnumStr[] = STRINGIZE(enum_list) ;                                  \   
  58. template<> const char * EnumHelper<enum_type_name>::s_typeName = (EnumHelper<enum_type_name>::SplitEnumDefString(), #enum_type_name);  
0 0
原创粉丝点击