zoukankan      html  css  js  c++  java
  • 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。不解释!










  • 相关阅读:
    混用Int与IntPtr导致GetProcAddress始终返回null
    Net中获取程序集路径
    Sql server 2014 同一数据库换名还原,导致同名库一直处于还原状态
    微耕N3000注入
    Xaramin IOS 开发常见问题
    Vs2017 xaramin mac build agent部署后记
    Git 笔记
    spring AOP
    JAVA 反射原理
    Hyperledger Fabric:fabric private data技术【官方文档翻译】
  • 原文地址:https://www.cnblogs.com/mthoutai/p/7142473.html
Copyright © 2011-2022 走看看