1. 程式人生 > >traits:Traits技術初探

traits:Traits技術初探

概述:
traits
是一種特性萃取技術,它在Generic Programming中被廣泛運用,常常被用於使不同的型別可以用於相同的操作,或者針對不同型別提供不同的實現.traits在實現過程中往往需要用到以下三種C++的基本特性:
enum
typedef
template
(partial) specialization
其中:
enum
用於將在不同型別間變化的標示統一成一個,它在C++中常常被用於在類中替代define,你可以稱enum為類中的define;
typedef
則用於定義你的模板類支援特性的形式,你的模板類必須以某種形式支援某一特性,否則型別萃取器traits將無法正常工作.看到這裡你可能會想,
太苛刻了吧?其實不然,不支援某種特性本身也是一種支援的方式(見示例2,我們定義了兩種標示,__xtrue_type__xfalse_type,分別表示對某特性支援和不支援).
template
(partial) specialization被用於提供針對特定型別的正確的或更合適的版本.藉助以上幾種簡單技術,我們可以利用traits提取類中定義的特性,並根據不同的特性提供不同的實現.你可以將從特性的定義到萃取,再到traits的實際使用統稱為traits技術,但這種定義使得traits顯得過於複雜,我更願意將traits的定義限於特性萃取,因為這種定義使得traits顯得更簡單,更易於理解,^
_^.

舉例:上面提到過,traits可被用於針對不同型別提供不同的實現,那麼下面就舉兩個例子來說明如何實現這一點.
Example 1:
假定我們需要為某個類設計一個可以對所有型別(包括普通的int/long...,提供了clone方法的複雜型別CComplexObject,及由該類派生的類)進行操作的函式clone,下面,先用OO的方法來考慮一下解決方案.看到前面的條件,最先跳進你腦子裡的肯定是Interface,pure virtual function等等.對於我們自己設計的類CComplexObject而言,這不是問題,但是,對於基本資料型別呢?還有那些沒有提供clone方法的複雜型別呢?(
這時候你可能會想,要是Java該多easy,所有類都預設從Object派生,Object已提供了一個預設的clone方法,但是,要使類真正支援clone,還必須implements Cloneable,所以,同樣也不能避免這裡遇到的麻煩).下面是一個可能的解決方案:
template
<typename T, bool isClonable>
class
XContainer
{
     ...

     void
clone(T* pObj)
     {

         if
(isClonable)
         {

             pObj->clone();
         }

         else

         {

             //... non-Clonable algorithm ...
         }
     }
};

但是隻要你測試一下,這段程式碼不能通過編譯.為什麼會這樣呢?原因很簡單:對於沒有實現clone方法的非Clonable類或基本型別,pObj->clone這一句是非法的.那麼怎樣解決上面的這個難題呢?上面不能通過編譯的程式碼告訴我們,要使我們的程式碼通過編譯,就不能使非Clonable類或基本型別的程式碼中出現pObj->clone,即我們需要針對不同型別提供不同的實現.為了實現這一點,我們可以在我們的模板類中用enum定義一個trait,以標示類是否為Clonable,然後在原模板類內部引入一個traits提取類Traits,通過對該類進行specilizing,以根據不同的trait提供不同的實現.具體實現如下:
#include <iostream>
using namespace std;

class
CComplexObject // a demo class{
public
:
     void
clone() { cout << "in clone" << endl; }
};


// Solving the problem of choosing method to call by inner traits class
template <typename T, bool isClonable>
class
XContainer
{

public
:
     enum
{Clonable = isClonable};

     void
clone(T* pObj)
     {

         Traits<isClonable>().clone(pObj);
     }


     template
<bool flag>
         class
Traits
     {
     };


     template
<>
         class
Traits<true>
     {

     public
:
         void
clone(T* pObj)
         {

             cout << "before cloning Clonable type" << endl;
             pObj->clone();
             cout << "after cloning Clonable type" << endl;
         }
     };


     template
<>
         class
Traits<false>
     {

     public
:
         void
clone(T* pObj)
         {

             cout << "cloning non Clonable type" << endl;
         }
     };
};


void
main()
{

     int
* p1 = 0;
     CComplexObject* p2 = 0;

     XContainer<int, false> n1;
     XContainer<CComplexObject, true> n2;

     n1.clone(p1);
     n2.clone(p2);
}

編譯執行一下,上面的程式輸出如下的結果:
doing something non Clonable
before doing something Clonable
in clone
after doing something Clonable
這說明,我們成功地根據傳入的isClonable模板引數為模板例項選擇了不同的操作,在保證介面相同的情況下,為不同型別提供了不同的實現.

Example 2:
我們再對上面的例子進行一些限制,假設我們的clone操作只涉及基本型別和CComplexObject及其派生類,那麼我們可以進一步給出下面的解法:
#include <iostream>
using namespace std;

struct
__xtrue_type { }; // define two mark-typestruct __xfalse_type { };

class
CComplexObject // a demo class{
public
:
     virtual
void clone() { cout << "in clone" << endl; }
};


class
CDerivedComplexObject : public CComplexObject // a demo derived class{
public
:
     virtual
void clone() { cout << "in derived clone" << endl; }
};


// A general edtion of Traits
template <typename T>
struct
Traits
{

     typedef
__xfalse_type has_clone_method; // trait 1: has clone method or not? All types defaultly has no clone method.};

// Specialized edtion for ComplexObject
template <>
struct
Traits<CComplexObject>
{

     typedef
__xtrue_type has_clone_method;
};


template
<typename T>
class
XContainer
{

     template
<typename flag>
         class
Impl
     {
     };

     template
<>
         class
Impl <__xtrue_type>
     {

     public
:
         void
clone(T* pObj)
         {

             pObj->clone();
         }
     };

     template
<>
         class
Impl <__xfalse_type>
     {

     public
:
         void
clone(T* pObj)
         {
         }
     };

public
:
     void
clone(T* pObj)
     {

         Impl<Traits<T>::has_clone_method>().clone(pObj);
     }
};


void
main()
{

     int
* p1 = 0;
     CComplexObject c2;
     CComplexObject* p2 = &c2;
     CDerivedComplexObject c3;
     CComplexObject* p3 = &c3; // you must point to a derived object by a base-class pointer,
                             //it's a little problem

     XContainer<int> n1;
     XContainer<CComplexObject> n2;
     XContainer<CComplexObject> n3;

     n1.clone(p1);
     n2.clone(p2);
     n3.clone(p3);
}

現在,所有基本型別以及CComplexObject類系都可以用於XContainer.結語:看到這裡,你或許會說,traits不過如此,還以為是什麼高深的玩意呢!其實技術就是這樣,說白了都很Easy,關鍵是怎麼將他們用於實際,為實際的Designing/Development服務.畢竟,IT領域,不能應用於實際的技術是沒有價值的.