boost::mpl::eval_if的使用方法
近期看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<//#1
boost::is_pointer<T>, boost::mpl::identity<PointerStruct<T>>,
boost::mpl::identity<DefaultStruct<T>>
>::type typex;//#1
这段代码非常easy推断T是否是一个指针,假设true,那么type的类型就是PointerStruct<T>,否则
type的类型是默认 DefaultStruct<T>。够简单吧,应该会用了吧。好。我们来个复杂一点的,由于
一个eval_if仅仅能推断一个类型。
我们想推断两个类型:
typedef
BOOST_DEDUCED_TYPENAME boost::mpl::eval_if<//#1
boost::is_pointer<T>, boost::mpl::identity<PointerStruct<T> >,
BOOST_DEDUCED_TYPENAME eval_if<//#2
boost::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<//#1
boost::is_pointer<T>, boost::mpl::identity<PointerStruct<T> >,
BOOST_DEDUCED_TYPENAME eval_if<//#2
boost::is_array<T>, boost::mpl::identity<ArrayStruct<T> >,
BOOST_DEDUCED_TYPENAME eval_if<//#3
boost::is_class<T>, boost::mpl::identity<ClassStruct<T> >,
BOOST_DEDUCED_TYPENAME eval_if<//#4
boost::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<//#1
boost::is_pointer<T>, boost::mpl::identity<PointerStruct<T> >,
BOOST_DEDUCED_TYPENAME eval_if<//#2
boost::is_array<T>, boost::mpl::identity<ArrayStruct<T> >,
BOOST_DEDUCED_TYPENAME eval_if<//#3
boost::is_class<T>, boost::mpl::identity<ClassStruct<T> >,
BOOST_DEDUCED_TYPENAME eval_if<//#4
boost::is_enum<T>, boost::mpl::identity<EnumStruct<T> >,
boost::mpl::identity<DefaultStruct<T> >
>//#4
>//#3
>//#2
>::type typex;//#1 typex::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);
}
呵呵。。。非常easy,但是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);
}
这个列子非常easy。不解释!
最新文章
- android 开启本地相册选择图片并返回显示
- 正确使用Python logging
- Trie树:POJ2001
- 如何手动让HttpRequestBase.IsAuthenticated 和 HttpContext.User.Identity.IsAuthenticated 为true.
- 从数据包谈如何封杀P2SP类软件
- 33-Url辅助方法
- API - .add()
- Android 虚拟机 Davlik
- PAT 字符串-02 删除字符串中的子串
- Gym 100507C	Zhenya moves from parents (线段树)
- Spring使用总结
- fedora -- java多版本切换
- DHTMLX 前端框架 建立你的一个应用程序教程(四)--添加一个工具条toolbar
- 处理器(CPU)调度问题
- asp.net通过配置文件设置默认页
- PHP三维数组拼装
- tomcat发布项目绑定域名总结
- ThinkPHP5从零基础搭建CMS系统(一)
- jmeter连接oracle时未找到要求的 FROM 关键字问题
- Linux学习笔记 11
热门文章
- laravel的socialite微信登录之用户信息
- fedora安装gcc
- SolidWorks的文件类型
- win下配置qt creator 能够执行c/c++
- CentOS 初体验十四:阿里云安装Gitlab
- VIM基础操作方法汇总
- 简谈Redis
- [Python3网络爬虫开发实战] 3.1-使用urllib
- 74-A/D指标,Accumulation/Distribution,积累/派发线,离散指标.(2015.7.1)
- vscode 解决符号无法识别的问题