程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 軟件架構設計之Utility模塊——Functor

軟件架構設計之Utility模塊——Functor

編輯:C++入門知識

一:前言          現在要實作一個泛化仿函數,泛化仿函數是將“請求(函數)封裝起來”,存儲與對象之中,該對象是具有“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 [cpp]   <span style="font-weight: normal;"><span style="font-size:14px;">template <class T, class U>   struct HTTypeList   {       typedef T Head;       typedef U Tail;   };</span></span>   這是typelist的基本實作(只需兩個類型),現在問題是如何把n個類型連成鏈表。看下面這個例子就明白了 [cpp]   typedef HTTypeList<char, HTTypeList<int, int> >   (利用模板參數推導,而且是編譯器自動產生,而不是運行期哦),這樣兩個以上的參數都解決了。          現在問題如何定義一個參數的typelist。方法是,第二個模板參數設為NullType(空類型),這樣每個typelist都以NullType結尾,相當於C字符串的\0功能。看NullType的實作: [cpp]   class HTNullType {};            接著就要生產typelist了(一個參數,兩個參數,三個參數……)。這裡用到宏,暫且定義4個typelist。 [cpp]   #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。 [cpp]   // 判斷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 };   };   [cpp]  // 依flag選擇兩個類型中的一個,true為T,false為U   template <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;   };   [cpp]   // 編譯期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更加的方便。下面直接看代碼。 [cpp]   // Functor對象明顯是個小對象,這裡采用小對象分配器   // 使用了Command模式及IMPL模式   template <typename R>   struct HTFunctorImplBase : public HTSmallObject<>   {       typedef R   ResultType;       typedef HTEmptyType Parm1;       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 R       ResultType;          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 R       ResultType;       typedef typename HTTypeTraits<P1>::ParmType   Parm1;          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 R       ResultType;       typedef typename HTTypeTraits<P1>::ParmType   Parm1;       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::Impl    Base;   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::Impl    Base;   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 R       ResultType;       typedef TList   ParmList;       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;   };    

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved