C++ 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-type
struct __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領域,不能應用於實際的技術是沒有價值的.


本文來自CSDN博客,轉載請標明出處:http://203.208.37.132/search?q=cache:LoX-IhgFPE0J:blog.csdn.net/tjieLy/archive/2009/05/30/4226916.aspx+c%2B%2B+traits&cd=1&hl=zh-CN&ct=clnk&gl=cn&st_usg=ALhdy29kNemU2LmZDiOU3SKG5Jj2GQ3Xog

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章