岁月流转,往昔空明

C++博客 首页 新随笔 联系 聚合 管理
  118 Posts :: 3 Stories :: 413 Comments :: 0 Trackbacks
这个设计主要是拿来保证跨组件的时候能尽可能的保护型别安全.

我今天晚上早些时候也往SoftArt里面提交了一个type to id的实现,使用宏和特化机制
但是这个版本的一个很大的问题就在于用起来不是很方便,每注册一个类需要2行代码,而且都是
#define PARAM float
#include REGTYPE()
这样的非常规的宏用法.
但是由于它是分类实现的,所以可以在里面补充一些额外的功能,比如自动的具名常量的生成.

所以晚上回来的时候又用boost的mpl写了一个原形,基本上是纯模板的.注册类只需要一行,但是宏实现版本中一些半自动化的特点也损失的差不多了.
回头还是要考虑用preprocessor结合MPL,看看能不能做到两个特点兼备.

mingw + gcc 4.2.1下通过

#include <iostream>
#include 
<boost/smart_ptr.hpp>

#include 
<boost/mpl/vector.hpp>
#include 
<boost/mpl/find.hpp>
#include 
<boost/mpl/at.hpp>
#include 
<boost/mpl/size.hpp>
#include 
<boost/mpl/if.hpp>
#include 
<boost/mpl/less.hpp>
#include 
<boost/mpl/int.hpp>
#include 
<boost/mpl/less_equal.hpp>

#include 
<boost/type_traits/is_same.hpp>

using namespace std;

struct empty{};

#define BEGIN_REGISTER_TYPE() typedef boost::mpl::vector<empty
#define REGISTER_TYPE(type) ,type
#define END_REGISTER_TYPE() > typelst;

namespace shader_constant
{
    BEGIN_REGISTER_TYPE()
        REGISTER_TYPE(
int)
        REGISTER_TYPE(
float)
        REGISTER_TYPE(
bool)
    END_REGISTER_TYPE();

    
static const int size_of_typelst = boost::mpl::size<typelst>::value;
    typedef boost::mpl::int_
<size_of_typelst> size_of_typelst_t;

    template
<class T>
    
struct type2id{
        typedef typename boost::mpl::find
<typelst, T>::type iter;
        
static const int id =
            boost::mpl::if_
<
                boost::is_same
<boost::mpl::end<typelst>::type, iter>,
                boost::mpl::int_
<0>,
                typename iter::pos
            
>::type::value;
    }
;

    template
<int id>
    
struct id2type{
        typedef boost::mpl::int_
<id> int_id;
        typedef boost::mpl::int_
<0> int_0;

        
//type = (0 < id && id <= size) ? typelst[id] : empty;
        typedef typename boost::mpl::if_<
            boost::mpl::and_
<
                boost::mpl::less
<int_0, int_id >,
                boost::mpl::less_equal
<int_id, boost::mpl::size<typelst>::type >
            
>,
            typename boost::mpl::at
<typelst, int_id>::type,
            empty
        
>::type type;
    }
;
}


using namespace shader_constant;

typedef 
void (*Assignments)(void* p1, void* p2);

template
<class T>
void AssignImpl(void* p1, void* p2)
{
    cout 
<< typeid(T).name() << endl;
    
*(T*)p1 = *(T*)p2;
}


template 
<> void AssignImpl<empty>(void* p1, void* p2)
{
    cout 
<< "error type!" << endl;
}


 Assignments assigns[size_of_typelst
+1];

template 
<int i>
struct assigns_initializer
{
    assigns_initializer
<i-1> m;
    assigns_initializer()
{
        assigns[i] 
= &AssignImpl<typename id2type<i>::type >;
        }

}
;

template 
<>
struct assigns_initializer<-1>
{
    assigns_initializer()
{
        }

}
;

static assigns_initializer<size_of_typelst> ai;

typedef 
double T;
int main()
{
    T i1(T(
0));
    T i2(T(
10));
    assigns[type2id
<T>::id](&i1, &i2);
    cout 
<< i1;
    system(
"pause");
    
return 0;
}

posted on 2008-03-08 00:55 空明流转 阅读(1273) 评论(4)  编辑 收藏 引用

评论

# re: 一个type2id的程序 2008-03-08 15:53 空明流转
新的实现,觉得还是这个好一点.
 
#include <iostream>
#include 
<boost/smart_ptr.hpp>

#include 
<boost/mpl/vector.hpp>
#include 
<boost/mpl/find.hpp>
#include 
<boost/mpl/at.hpp>
#include 
<boost/mpl/size.hpp>
#include 
<boost/mpl/if.hpp>
#include 
<boost/mpl/less.hpp>
#include 
<boost/mpl/int.hpp>
#include 
<boost/mpl/less_equal.hpp>

#include 
<boost/type_traits/is_same.hpp>
#include 
<boost/preprocessor/seq/for_each.hpp>
#include 
<boost/preprocessor/seq/for_each_i.hpp>

using namespace std;

struct empty{};

#define TYPE_LST \
(empty) \
(
bool)(float)(int)

#define BEGIN_ENUM() enum ENUM_NAME {
#define REG_ENUM(r, data, i, type_elem) BOOST_PP_CAT(ENUM_PRED, type_elem) = i,
#define END_ENUM() };

#define BEGIN_ENCODE_DECODE()    \
template
<class T>    struct type_encodestatic const int id = 0static const ENUM_NAME tag = ENUM_NAME(0); };\
template
<int i> struct type_decode{ typedef empty type;};

#define REGISTER_TYPE(r, dummy, i, type_elem) \
template
<> struct type_encode< type_elem >{static const int id = i; static const ENUM_NAME tag = ENUM_NAME(i);};\
template
<> struct type_decode< i >{typedef type_elem type;};

#define END_ENCODE_DECODE()
enum s{
    ebool
}
;

namespace shader_constant
{
    
#define ENUM_NAME sh_typeids
    
#define ENUM_PRED sh_typeids
    
#define ENUM_POST
    BEGIN_ENUM()
    BOOST_PP_SEQ_FOR_EACH_I(REG_ENUM, _, TYPE_LST)
    END_ENUM()

    BEGIN_ENCODE_DECODE()
    BOOST_PP_SEQ_FOR_EACH_I(REGISTER_TYPE, _, TYPE_LST)
    END_ENCODE_DECODE()

    
const int size_of_typelst = BOOST_PP_SEQ_SIZE(TYPE_LST);
}


using namespace shader_constant;

typedef 
void (*Assignments)(void* p1, void* p2);

template
<class T>
void AssignImpl(void* p1, void* p2)
{
    cout 
<< typeid(T).name() << endl;
    
*(T*)p1 = *(T*)p2;
}


template 
<> void AssignImpl<empty>(void* p1, void* p2)
{
    cout 
<< "error type!" << endl;
}


 Assignments assigns[size_of_typelst
+1];

template 
<int i>
struct assigns_initializer
{
    assigns_initializer
<i-1> m;
    assigns_initializer()
{
        assigns[i] 
= &AssignImpl<typename type_decode<i>::type >;
        }

}
;

template 
<>
struct assigns_initializer<-1>
{
    assigns_initializer()
{
        }

}
;

static assigns_initializer<size_of_typelst> ai;

typedef 
double T;
int main()
{
    T i1(T(
0));
    T i2(T(
10));
    assigns[type_encode
<T>::id](&i1, &i2);
    cout 
<< i1;
    system(
"pause");
    
return 0;
}

  回复  更多评论
  

# re: 一个type2id的程序 2008-03-08 22:28 橙子
可有看过《C++设计新思维》 ?
里面有一章Typtlist,专门讲这个。你这个看起来很高深。  回复  更多评论
  

# re: 一个type2id的程序 2008-03-09 11:39 空明流转
typelist有typelist不妥的地方。
我的原帖解法就是typelist的(boost::mpl::vector)。
但是typelst的解法中,它的类型名称信息只能用一次,而我在做枚举或者别的时候需要再次利用这个类型名称生成合适的枚举值名称或者别的什么。
所以我用了boost的preprocessor作为确定序列的工具。  回复  更多评论
  

# re: 一个type2id的程序 2008-03-21 19:06 李锦俊
空明你的程序我越来越怕了。那么多宏+模板,晕啊。  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理