boost::mpl::eval_if的用法

来源:互联网 发布:long型数据的取值范围 编辑:程序博客网 时间:2024/06/06 23:30
最近看boost的时候总是遇见这个eval_if,不知道啥意思,就没法看下去了,比如

前篇文章boost::serialization 拆分serialize函数分析时就出现这样一段代码:

template<class Archive, class T>inline void split_member(Archive & ar, T & t, const unsigned int file_version){typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<BOOST_DEDUCED_TYPENAME Archive::is_saving,mpl::identity<detail::member_saver<Archive, T> >, mpl::identity<detail::member_loader<Archive, T> >>::type typex;typex::invoke(ar, t, file_version);}
就去看看boost文档解释如下:

typedef eval_if<c,f1,f2>::type t;Return type:Any type.Semantics:If c::value == true, t is identical to f1::type; otherwise t is identical to f2::type.
就是加入c::value 为TRUE就返回f1::type,否则就返回f2::type。
然后给了一个一列子:

typedef eval_if< true_, identity<char>, identity<long> >::type t1;typedef eval_if< false_, identity<char>, identity<long> >::type t2;BOOST_MPL_ASSERT(( is_same<t1,char> ));BOOST_MPL_ASSERT(( is_same<t2,long> ));
自己动手试试,用法还是蛮简单的,而且还可以递归实用。
看下面一个简单的例子:

//定义两个结构体template<typename T>struct PointerStruct{typedef T* PointerT;static void print(){std::cout << typeid(PointerT).name() << std::endl;}};template<typename T>struct DefaultStruct{static void print(){std::cout << "default is called!" << std::endl;}};
然后来实现一个判断T是否是指针类型:

typedef typename boost::mpl::eval_if<//#1boost::is_pointer<T>, boost::mpl::identity<PointerStruct<T>>, boost::mpl::identity<DefaultStruct<T>>>::type typex;//#1
这段代码很简单判断T是否是一个指针,如果true,那么type的类型就是PointerStruct<T>,否则
type的类型是默认 DefaultStruct<T>。够简单吧,应该会用了吧!好,我们来个复杂一点的,因为
一个eval_if只能判断一个类型。
我们想判断两个类型:

typedef BOOST_DEDUCED_TYPENAME boost::mpl::eval_if<//#1boost::is_pointer<T>, boost::mpl::identity<PointerStruct<T> >,BOOST_DEDUCED_TYPENAME eval_if<//#2boost::is_array<T>, boost::mpl::identity<ArrayStruct<T> >,boost::mpl::identity<DefaultStruct<T>>>//#2>::type typex;//#1

注意#1 #2是成对出现的,这就是递归模板的一个典型应用!这样就可以判断两个类型的:是指针韩式数组
下面示范了能够判断多类型的列子:

typedef BOOST_DEDUCED_TYPENAME boost::mpl::eval_if<//#1boost::is_pointer<T>, boost::mpl::identity<PointerStruct<T> >,BOOST_DEDUCED_TYPENAME eval_if<//#2boost::is_array<T>, boost::mpl::identity<ArrayStruct<T> >,BOOST_DEDUCED_TYPENAME eval_if<//#3boost::is_class<T>, boost::mpl::identity<ClassStruct<T> >,BOOST_DEDUCED_TYPENAME eval_if<//#4boost::is_enum<T>, boost::mpl::identity<EnumStruct<T> >, boost::mpl::identity<DefaultStruct<T> >>//#4>//#3>//#2>::type typex;//#1
现在我们已经能够写出判断任一类型(boost支持很多类型的判断)的eval_if用法。现在我们
应该想想怎么应用 eval_if ,看到结构体里面的print函数吗,我们可以为不同的类型实现
不同的print方法,然后在确定类型后我们只需要调用:
typex::print();
比如T是一个pointer,那么typex的类型就是PointerStruct<T>,那么上面哪句代码就等于调用:
PointerStruct<T>::print();
这样是不是很厉害,加入我们有很多不同的方法要调用时,我们可以给每个方法用结构体包装,
然后在这个结构体里面实现方法。然后用类型去确定调用那些方法。
首先实现用结构体包装我们要调用的方法:
为简单这里仅实现输出类型....

template<typename T>struct PointerStruct{typedef T* PointerT;static void print(){std::cout << typeid(PointerT).name() << std::endl;//do what you want to do...}};template<typename T>struct EnumStruct{static void print(){std::cout << typeid(T).name() << std::endl;//do what you want to do...}};template<typename T>struct ArrayStruct{static void print(){std::cout << "this is " << typeid(T).name() << std::endl;//do what you want to do...}};template<typename T>struct ClassStruct{static void print(){std::cout << typeid(T).name() << std::endl;//do what you want to do...}};template<typename T>struct DefaultStruct{static void print(){std::cout << "default is called!" << std::endl;//do what you want to do...}};
然后在实现一个包装eval_if的函数,在这个函数里面实现根据类型来调用相应的函数:

template<typename T>inline void printTypeOfT(const T& t){using namespace boost::mpl;typedef BOOST_DEDUCED_TYPENAME boost::mpl::eval_if<//#1boost::is_pointer<T>, boost::mpl::identity<PointerStruct<T> >,BOOST_DEDUCED_TYPENAME eval_if<//#2boost::is_array<T>, boost::mpl::identity<ArrayStruct<T> >,BOOST_DEDUCED_TYPENAME eval_if<//#3boost::is_class<T>, boost::mpl::identity<ClassStruct<T> >,BOOST_DEDUCED_TYPENAME eval_if<//#4boost::is_enum<T>, boost::mpl::identity<EnumStruct<T> >, boost::mpl::identity<DefaultStruct<T> >>//#4>//#3>//#2>::type typex;//#1typex::print();//公共接口}
这样ok了,现在测试一个:

class TestClass{};enum Type{a,b,c};void fun0(){int* pInt = NULL;printTypeOfT(pInt);Type xT;printTypeOfT(xT);float Array[] = {0.0f, 1.0f};printTypeOfT(Array);TestClass TC;printTypeOfT(TC);float yF;printTypeOfT(yF);}

呵呵。。。很简单,可是eval_if却是有很多宏来实现的,有些宏没看懂!。。。先会用再说!

下面还有一个列子,这是boost::serialization 拆分serialize函数里面那个split_member函数就是采用eval_if来实现,

这里简单模拟一个:

class text_iarchive{public:typedef boost::mpl::bool_<true> is_loading;typedef boost::mpl::bool_<false> is_saving;};class text_oarchive{public:typedef boost::mpl::bool_<false> is_loading;typedef boost::mpl::bool_<true> is_saving;};class access{public:template<typename Archive, class T>static void save(Archive& ar, T& t,const unsigned int file_version){t.save(ar, file_version);}template<typename Archive, class T>static void load(Archive& ar, T& t,const unsigned int file_version){t.load(ar, file_version);}};class test_class{private:friend class access;template<typename Archive>void save(Archive& ar, const unsigned int file_version){std::cout << BOOST_CURRENT_FUNCTION << " " << &(*this) << std::endl;}template<typename Archive>void load(Archive& ar, const unsigned int file_version){std::cout << BOOST_CURRENT_FUNCTION << " " << &(*this) << std::endl;}};template<typename Archive, class T>struct member_saver{static void invoke(Archive& ar, T& t,const unsigned int file_version){access::save(ar, t, file_version);}};template<typename Archive, class T>struct member_loader{static void invoke(Archive& ar, T& t,const unsigned int file_version){access::load(ar, t, file_version);}};template<typename Archive, class T>void split_member(Archive& ar, T& t,const unsigned int file_version){typedef BOOST_DEDUCED_TYPENAME boost::mpl::eval_if<BOOST_DEDUCED_TYPENAME Archive::is_saving, boost::mpl::identity<member_saver<Archive, T> >,boost::mpl::identity<member_loader<Archive, T> >>::type typex;typex::invoke(ar, t, file_version);}void fun(){text_iarchive ia;text_oarchive oa;test_class tc;split_member(ia, tc, 1);split_member(oa, tc, 1);}
这个列子很简单,不解释!








0 0