C++模板的原理與應用

相信大家對模板並不陌生,模板的基本概念我想就不用多說了。大多數人包括我自己對模板的理解就是“T容器”。

請看下面的代碼:

 

template<int m1int l1int t1int m2int l2int t2>

Physical<m1+m2l1+l2t1+t2operator *Physical<m1l1t1 > lhsPhysical<m2l2t2rhs)

{

    return Physical<m1+m2l1+l2t1+t2>::unit * lhs.value() * rhs.value();

}

 

頭一次見到template的這種用法時,我確實有點目眩。看來我們對模板的認識只是皮毛而已 J

 

在當今的程序設計中模板已經顯露出它的價值來了,比如STL全部都是以模板架構的。VS2003(VC7)以來的編譯器也對模板提供了更多的支持。

 

我們需要對模板有更進一步的認識,下面就讓我們進入模板的世界。

 

 

  • 模板的特性

首先來看一個例子:

 

template<int n>

int Func1()     { return n; }

int Func2(int n) { return n; }

 

你能看出這兩個函數的區別在哪裏嗎?

它們的區別就在於,Func1的參數是編譯期指定,如Func1<0>() ;而Func2的參數則是運行期指定。

 

這正體現了模板的特性或者說是它的技術核心,就是編譯期的動態機制這種機制使程序在運行期具有更大的效率優勢

到此你是不是對本文開頭那段代碼有了更深入的理解了呢?

 

模板的另一個特性是,如果一個模板沒有被特化,那麼編譯器根本不會去理會它,也就是說模板內的代碼被隱藏了。

 

 

  • 函數模板與類模板

這是一個函數模板:template<class T> Func(T param) {}

函數模板的模板參數是隱式的,編譯器會自動根據傳入值的類型來確定模板參數的類型。因此函數模板的模板參數不能有默認值

 

這是一個類模板:template<class T> class MyClass {};

類模板的模板參數是顯式的,使用一個模板類時必須指明其模板參數,因此類模板的模板參數可以有默認值

我們還可以做更多的事情,比如MyClass可以派生自TXTP界面庫就是這麼做的),在MyClass內部可以使用關於Tenumtypedef等等。這些將在下文一一談到。

 

(我在這裏提出一個建議,創建一個類模板,請記得第一件事就是對模板參數進行typedef定義。)

 

 

  • 模板的部分特化與應用

模板最有價值的地方就是它的部分特化,也是應用最廣泛的特性。

所謂“部分特化”也就是說,一個模板有多個參數,但我們只對其中一部分參數進行特化,或者是隻針對常量模板參數的某種情況進行特化。

 


編譯期ASSERT

這是對bool型模板參數部分特化的一個例子。最簡單的實現:

 

template<boolstruct CompileTimeAssert;

template<> struct CompileTimeAssert<true> {};

 

當我們將一個表達式作爲模板參數,而這個表達式的值爲false時,編譯器就找不到合適的實現,便會報錯了。

 

我們可以將它擴展一下:

template<boolstruct CompileTimeAssert { CompileTimeAssert(…) ;};  // 這裏使用了C++支持的任意參數表

template<> struct CompileTimeAssert<false> {};

 

#define COMPILE_CHECK(exprmsg) /

{/

            class ERROR_##msg {}; /

            (voidCompileTimeAssert<((expr)!=0)>(ERROR_##msg()); /

}

   // 這裏不直接傳入expr是爲了獲得更大的適應性,因爲expr有可能是無法隱式轉換爲bool型的(比如指針),筆者曾參與的

  // 一個項目在由VC6平臺升級到VS2003平臺時,由於後者ASSERT宏實現的變化,就遇到了這一問題。

 

當然,事實是編譯期可用的表達式或函數(如sizeof__alignof數量上並不太多,但是這種方式是有着積極意義的。

 

編譯期分派與類型選擇

 

常量映射爲類型

請看這樣一個模板:template<int vstruct Int2Typeenumvalue = v }; };

模板參數的不同數值,就會產生不同類型的Int2Type。即Int2Type<0>不同於Int2Type<1>,以此類推。

 

我們可以利用這個模板實現編譯期分派。看這樣一個例子:

 

template<class T, bool bPolymorphic>

class MyClass

{

    ……

    void Func(T* pObj)

{

    if (bPolymorphic)

{

    T* pNewObj = pObj->Clone();  // 多態類型

……

}

else

{

    T* pNewObj = new T(*pObj);  // 非多態類型

……

}

}

};

 

顯然,編譯器不會讓你僥倖成功。而使用了

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