c++模版的一些使用方法(三)

c++模版的應用是可以分類的。按照用途,可以分爲:

  1)工程模版

  2)算法和數據結構的解耦

  3)工作於編譯期的模版

  4)XX的封裝

  5)適配器模式

首先解釋一下,這裏的劃分屬於較高層的應用劃分,但這些應用都是基於模版的一些共同特性的,比如帶默認參數、特化和偏特化等。

分別解釋一下就是:

(1)工程模版:《c++模版的一些使用方法(一)》中提到修改第三方庫的應用屬於這一類。工程模版主要是在大工程中的一些處理手法,不太好說。


(2)算法和數據結構的解耦就很清晰了,比如stl庫,find算法既可以用於vector也可以用於list。再比如經常使用的單件模式,將它聲明爲幾類,任何需要是單件模式的類只要從這個基類派生即可獲得單件屬性

template<typename T>
class Singleton
{
protected:
        Singleton(){}
public:
    static T& GetInstance()
        {
            static T Instance;
            return Instance; 
        }
};

class MyClass:public Singleton<MyClass>
{};


(3)工作於編譯期的模版

由代碼到可執行文件分爲幾個階段:

No.1預處理階段:處理#define,#ifdef,#include等預處理指令。它使在編譯之前提供了一次修改源文件的機會,具有很大的靈活性。

No.2編譯期:將源代碼編成機器碼,每個模塊生成obj文件,

No.3鏈接器:將n個obj文件組合在一起,解析他們之間的交叉關係,得到可執行文件。

平時我們所說的執行效率,是指可執行文件處理一組數據的效率,可能還聽說過在程序設計比賽中可以利用預處理來做一些事情,以此減少程序處理數據的時間,那麼同樣,有些事情是可以在編譯期做的,同樣可以通過把一些事情提前到編譯期來提高程序的效率。

首先要明白哪些工作可以在編譯期做:

No.1當有函數重載時,編譯器在編譯期決定調用哪個函數;

No.2sizeof操作符,typedef操作符,+ - = < > :?等運算符,等等等

No.3enum類型的賦值

No.4模版的特化、偏特化和實例化

那麼,可以在編譯期做哪些事呢?

我總結的有兩點:

    1)計算一些數據

    2)生成代碼

計算數據時,比如,可以這樣計算Fibonacci數列:

template<int N>
struct Fibonacci
{
    enum
    {
        result = Fibonacci<N-1>::result+Fibonacci<N-2>::result
    };
};
template<>
struct Fibonacci<1>
{
    enum
    {
        result =1
    };
};
template<>
struct Fibonacci<0>
{
    enum
    {
        result =0
    };
};
int main()
{
    time_t t1=time(NULL);
    printf("%d\n",Fibonacci<40>::result);
    time_t t2=time(NULL);
    printf("UseTime:%d\n",t2-t1);
    return 1;
};
首先定義了一個模版,還有它的兩個特化(針對1和0),接着調用Fiboncaai<40>::result,則編譯器在編譯時會嘗試給模版中enum::result賦值,賦的是它後面那個表達式,而後面的表達式是一個另外兩個模版的實例化,這同樣也發生在編譯期,所以編譯器會繼續跟下去,一直跟到Fiboncaai<1>::result+Fiboncaai<0>,然後編譯器發現針對1和0是有模版特化的,於是它去調用特化,特化中定義了出口,於是賦值結束。可以將其理解爲類遞歸,但不同的是,真正意義的遞歸是函數的嵌套調用本身,時間複雜度很高,而這裏,由於在編譯器,每次“遞歸”實質上是模版的實例化,而出口是模版的特化,所以不存在任何的函數嵌套調用。

上面Fiboncaai<40>輸出的結果是102334155,反彙編看一下,如圖:


編譯器經過計算,直接在這裏放了一個立即數,譯成十進制正是102334155

而上面代碼中所消耗的時間是0。如圖


而經過測試,用普通的函數遞歸計算Fiboncaai的第40個,需要8秒的時間。

用於生成代碼時,也可以成爲模版的元編程,元編程是指某類計算機程序的編寫,這類計算機程序編寫或者操縱其他程序(或者自身)作爲它們的數據,或者在編譯時完成部分本應在運行時完成的工作。很多情況下比手工編寫全部代碼相比工作效率更高。編寫元程序的語言稱之爲元語言,被操作的語言稱之爲目標語言。一門語言同時也是自身的元語言的能力稱之爲反射。

由上面的定義可知,元編程也是工作在編譯期,其實上面的計算數據的應用,也可以歸爲元編程,因爲編譯器不斷的實例化模版來“遞歸”,本質上也是在幫我們生成代碼。Loki庫中的Typelist就是使用模版元編程的經典之作。

XX的封裝和適配器模式以後再說吧

發佈了56 篇原創文章 · 獲贊 21 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章