软件架构设计之Utility模块——Functor
来源:互联网 发布:淘宝怎么认证中国制造 编辑:程序博客网 时间:2024/05/19 09:38
一:前言
现在要实作一个泛化仿函数,泛化仿函数是将“请求(函数)封装起来”,存储与对象之中,该对象是具有“value语义”的,因此它支持拷贝,赋值和作为函数参数来传值(pass by value)。通过该对象可间接的处理它封装的请求,类似于boost 中的function功能。本实现采用的是《Modern C++ Design》中的方案。更详尽的说,它具有以下特点:
1. 可封装任何处理请求,它可接受函数指针,成员函数指针,仿函数,甚至其它泛化仿函数。
2. 具备型别安全性,不会将错误的型别匹配到错误的函数上。
3. 是一种带有“value语义的对象”。
首先介绍下C++中的可调用体:
1. C风格的函数(C like function): void fun();
2. C风格的函数指针(C like pointto function): void (*pFun)();
3. 函数引用(reference to function),其行为本质上和const pointer to function类似。
4. 仿函数(functor),类中自定义了operator () 的对象。
5. Operator.*和operator->*的施行结果
6. 构造函数
在上述的任一项,你可以在其右侧添加一对圆括号(),并在里头放入一组合适的参数。
先来讨论这样一个问题,既然想把函数请求封装到对象中,函数的参数如何确定?这里使用typelist(这是一个型别集,换句话说它包含型别列表)。这里就可以把typelist作为HTFunctor的一个模板参数,它包含所要封装函数的参数型别信息。下面就先介绍下typelist实作
二:HTTypeList
template <class T, class U>struct HTTypeList{typedef T Head;typedef U Tail;};
这是typelist的基本实作(只需两个类型),现在问题是如何把n个类型连成链表。看下面这个例子就明白了
typedef HTTypeList<char, HTTypeList<int, int> >
(利用模板参数推导,而且是编译器自动产生,而不是运行期哦),这样两个以上的参数都解决了。
现在问题如何定义一个参数的typelist。方法是,第二个模板参数设为NullType(空类型),这样每个typelist都以NullType结尾,相当于C字符串的\0功能。看NullType的实作:
class HTNullType {};
接着就要生产typelist了(一个参数,两个参数,三个参数……)。这里用到宏,暂且定义4个typelist。
#define TYPELIST_1(T1) UTIL::HTTypeList<T1, UTIL::HTNullType>#define TYPELIST_2(T1, T2) UTIL::HTTypeList<T1, TYPELIST_1(T2) >#define TYPELIST_3(T1, T2, T3) UTIL::HTTypeList<T1, TYPELIST_2(T2, T3) >#define TYPELIST_4(T1, T2, T3, T4) UTIL::HTTypeList<T1, TYPELIST_3(T2, T3, T4) >
另外要解决的问题是,函数参数该是值类型(内部内型)还是引用类型(对于对象)。选择合适的类型显然能提高程序速度,你肯定不想传递大对象参数时而要额外拷贝。接下来这个东西就要登场了——(HTTypeTraits)
三:HTTypeTraits
可用于“编译期根据型别作判断”的泛型技术。大家也可参看boost中的type traits。
// 判断T及U是否标示同一个类型template <typename T, typename U>struct HTIsSameType{private:template<typename>struct In { enum { value = false }; };template<>struct In<T>{ enum { value = true }; };public:enum { value = In<U>::value };};
// 依flag选择两个类型中的一个,true为T,false为Utemplate <bool flag, typename T, typename U>struct HTSelect{private:template<bool>struct In { typedef T Result; };template<>struct In<false>{ typedef U Result; };public:typedef typename In<flag>::Result Result;};
// 编译期bool型typedef char HTYes;struct HTNo { char padding[8]; };// 型别映射为型别,用于模板函数的偏特化,C++标准模板函数不能偏特化template <typename T>struct HTType2Type { typedef T Type; };// 判断T是否为类template <typename T>struct HTIsClass{// U为类的话,会具现化此重载函数,因为参数为函数指针,即指向成员的函数指针template <typename U> static HTYes IsClassTest(void(U::*)(void));// U为非类,会具现化此重载函数// C++标准:只有当其它所有的重载版本都不能匹配时,具有任意参数列表的重载版本才会被匹配template <typename U> static HTNo IsClassTest(...);// 对于sizeof,表达式不会被真正求值,编译器只推导出表达式的返回结果的型别,因此只需函数的声明即可static const bool value = sizeof(IsClassTest<T>(0)) = sizeof(HTYes);};// 判断T是否为引用类型template <typename T>struct HTIsReference{template <typename U> static HTYes IsReference(HTType2Type<U&>);template <typename U> static HTNo IsReference(...);static const bool value= sizeof(IsReference(HTType2Type<T>())) == sizeof(HTYes);};template <typename T>class HTTypeTraits{public:enum { isVoid = HTIsSameType<T, void>::value ||HTIsSameType<T, const void>::value ||HTIsSameType<T, volatile void>::value ||HTIsSameType<T, const volatile void>::value};enum { isReference = HTIsReference<T>::value };private:template<bool IsRef>struct AdjReference{template<typename U>struct In { typedef U const & Result; };};template<>struct AdjReference<true>{template<typename U>struct In { typedef U Result; };};typedef typename AdjReference<isReference || isVoid>::template In<T>::Result AdjType;// 正确的选择函数参数的类型// 对于精巧型(有构造函数和析构函数额外调用)采用引用传参数,对于纯量型(数值型别,枚举型别,指针,指向成员的指针)采用直接传值typedef typename HTSelect<HTIsClass<T>::value, AdjType, T>::Result ParmType;};
四:HTFunctor
HTTypeList及HTTypeTraits提供我们强大的功能。这让我们实作HTFunctor更加的方便。下面直接看代码。
// Functor对象明显是个小对象,这里采用小对象分配器// 使用了Command模式及IMPL模式template <typename R>struct HTFunctorImplBase : public HTSmallObject<>{typedef RResultType;typedef HTEmptyTypeParm1;typedef HTEmptyType Parm2;};template <typename R, class TList, class ObjClass>struct HTFunctorImpl;// 无参数版本template <typename R, class ObjClass>struct HTFunctorImpl<R, HTNullType, ObjClass> : public HTFunctorImplBase<R>{typedef RResultType;virtual ResultType operator()(ObjClass* pObj) = 0;virtual HTFunctorImpl* Clone() const = 0;virtual ~HTFunctorImpl() {}};// 一个参数版本template <typename R, typename P1, class ObjClass>struct HTFunctorImpl<R, TYPELIST_1(P1), ObjClass> : public HTFunctorImplBase<R>{typedef RResultType;typedef typename HTTypeTraits<P1>::ParmTypeParm1;virtual ResultType operator()(Parm1, ObjClass* pObj) = 0;virtual HTFunctorImpl* Clone() const = 0;virtual ~HTFunctorImpl() {}};// 两个参数版本template <typename R, typename P1, typename P2, class ObjClass>struct HTFunctorImpl<R, TYPELIST_2(P1, P2), ObjClass> : public HTFunctorImplBase<R>{typedef RResultType;typedef typename HTTypeTraits<P1>::ParmTypeParm1;typedef typename HTTypeTraits<P2>::ParmType Parm2;virtual ResultType operator()(Parm1, Parm2, ObjClass* pObj) = 0;virtual HTFunctorImpl* Clone() const = 0;virtual ~HTFunctorImpl() {}};// 可调用体(即封装的处理函数)为仿函数template <class ParentFunctor, typename Fun, class ObjClass>class HTFunctorHandler : public HTFunctorImpl< typename ParentFunctor::ResultType,typename ParentFunctor::ParmList,ObjClass>{typedef typename ParentFunctor::ImplBase;public:typedef typename Base::ResultType ResultType;typedef typename Base::Parm1 Parm1;typedef typename Base::Parm1 Parm2;HTFunctorHandler(const Fun& fun) : m_fun(fun) {}HTFunctorHandler* Clone() const { return new HTFunctorHandler(*this); }ResultType operator()(ObjClass* pObj) { return m_fun(); }ResultType operator()(Parm1 p1, ObjClass* pObj){ return m_fun(p1); }ResultType operator()(Parm1 p1, Parm2 p2, ObjClass* pObj){ return m_fun(p1, p2); }private:Fun m_fun;};// 可调用体(即封装的处理函数)为类成员函数,调用需传递对象指针template <class ParentFunctor, typename Fun, class ObjClass>class HTMemFunHandler : public HTFunctorImpl< typename ParentFunctor::ResultType,typename ParentFunctor::ParmList,ObjClass>{typedef typename ParentFunctor::ImplBase;public:typedef typename Base::ResultType ResultType;typedef typename Base::Parm1 Parm1;typedef typename Base::Parm1 Parm2;HTMemFunHandler(const Fun& fun) : m_fun(fun) {}HTMemFunHandler* Clone() const { return new HTMemFunHandler(*this); }ResultType operator()(ObjClass* pObj) { return (pObj->*m_fun)(); }ResultType operator()(Parm1 p1, ObjClass* pObj) { return (pObj->*m_fun)(p1); }ResultType operator()(Parm1 p1, Parm2 p2, ObjClass* pObj){ return (pObj->*m_fun)(p1, p2); }private:Fun m_fun;};// HTFunctor实现体template <typename R, class TList = YKNullType, class ObjClass = YKEmptyType>class HTFunctor{typedef HTFunctorImpl<R, TList, ObjClass> Impl;public:typedef RResultType;typedef TListParmList;typedef typename Impl::Parm1 Parm1;typedef typename Impl::Parm2 Parm2;HTFunctor() : m_spImpl() {}HTFunctor(const HTFunctor& rhs) : m_spImpl(rhs.m_spImpl->Clone()) {}explicit HTFunctor(std::auto_ptr<Impl> spImpl) : m_spImpl(spImpl) {}HTFunctor& operator=(const HTFunctor& rhs){HTFunctor copy(rhs);Impl* p = m_spImpl.release();m_spImpl.reset(copy.m_spImpl.release());copy.m_spImpl.reset(p);return *this;}template <typename Fun>HTFunctor(Fun fun): m_spImpl(new HTSelect<HTIsSameType<ObjClass, HTEmptyType>::value, HTFunctorHandler<HTFunctor, Fun, ObjClass>, HTMemFunHandler<HTFunctor, Fun, ObjClass> >::Result(fun)){}ResultType operator()(ObjClass* pObj = HT_NULL) {return (*m_spImpl)(pObj);}ResultType operator()(Parm1 p1, ObjClass* pObj = HT_NULL) {return (*m_spImpl)(p1, pObj);}ResultType operator()(Parm1 p1, Parm2 p2, ObjClass* pObj = HT_NULL) {return (*m_spImpl)(p1, p2, pObj);}private:std::auto_ptr<Impl> m_spImpl;};
- 软件架构设计之Utility模块——Functor
- 软件架构设计之Utility模块——内存分配
- 软件架构设计之Utility模块——智能指针
- 软件架构设计之Utility模块——string
- 软件架构设计之Utility模块——DateTime
- 软件架构设计之Utility模块——Any
- Functor——转发
- Functor——Impl
- Functor——bind
- Functor——周边
- c++ 泛型 编程 之 Functor 设计模式
- 软件架构设计之导读
- 软件架构之——好的架构是进化来的,不是设计来的
- 软件架构设计之常用架构模式
- 软件架构设计之常用架构模式
- 软件架构设计之七:软件架构设计
- 软件架构——设计原则
- 软件架构——设计原则
- hql
- android API之ActivityGroup
- 读取文件到结构体
- BOJ 652
- Com开发之回调
- 软件架构设计之Utility模块——Functor
- 实验十三 SCVMM克隆和虚拟机模版
- A la Carte Pattern, Consulting Pattern Series
- windows下开发板的网络配置
- 为什么整合Spring与Struts2的时候,必须定义Struts2 Bean的Scope
- 利用libpcap库采集网口数据
- 设计模式六大原则(1):单一职责原则
- 最近写的一个makefile,可以配置编成elf,静态库,动态库
- ioctl等