Traits技術初探

來源:互聯網
上載者:User
概述 :
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而言,這不是問題,但是,對於基礎資料型別 (Elementary Data Type)呢?還有那些沒有提供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領域,不能應用於實際的技術是沒有價值的.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.