zoukankan      html  css  js  c++  java
  • 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;
    }

    输出结果如下:

    image

    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);
  • 相关阅读:
    使用 mysql_random_data_load 生成随机数据
    TeamViewer 运行 AlterID 时候报错Cloud not create a fake UUID
    1.6 在WHERE子句中引用取别名的列
    本地登录多实例mysql ,默认登录数据库问题
    统计前10位的占用空间较大的目录
    Oracle查看用户权限
    [LeetCode]Binary Tree Preorder Traversal
    [LeetCode]Insertion Sort List
    [LeetCode]Implement strStr()
    [LeetCode]Remove Element
  • 原文地址:https://www.cnblogs.com/quark/p/2208241.html
Copyright © 2011-2022 走看看