混沌 IN C++::Template Metaprograms

難度:star.gifstar.gifstar.gifstar.gif

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

文前說明:文中涉及到的觀點並不是要求你去遵循它,而本文只相當於一篇“科普文章”。其中的關於template的語法在這裏就不過多介紹了。例如,下文中提到的條件,都是要意識到是編譯期常量。

C++ template 爲我們提供了編譯期計算的功能。編譯器在處理template時,實際上相當於一個解釋器的作用。充分利用template可以提高代碼的運行速度,可以降低代碼維護的複雜度,還可以爲代碼提供更具擴展性的能力。下面就嘗試一下這樣的編程方式。

 

一、  C++ template替代if/if-else語句

if(條件)

語句1;

else

語句2;

   

C++ template中,我們可以這樣寫

template<bool cond>

struct my_if{};

 

template<>

struct my_if<true>{

static void go()

{ 語句1; }

};

 

template<>

struct my_if<false>{

static void go()

{ 語句2; }

};

 

例如,我們判斷兩個整數

my_if<(1<5)>::go();

也許你會覺得這個if/if-elsetemplate有點大提小做的感覺,呵呵,繼續往下看

 

二、  C++ template版的if/if-else擴展成能應付switch的代碼

如果你是一個面向對象編程的高手,你肯定不會在你的代碼中安置switch這樣的代碼,你肯定會用通過抽象、繼承、多態和接口來完成這個任務。不過現在要換一個思維,用C++ template來實現。其實這裏的代碼和上面的if/if-else相差無幾,但是在用於switch時,也同樣能出色地體現出OC原則。

int i;

switch(i)

{

   case 1;

       語句1;

       break;

   case 2;

       語句2;

       break;

     default:

       語句3;

}

 

下面是C++ template版本

template<int I>

struct my_switch{

    static void go(){

         語句3;

}

};

 

template<>

struct my_switch<1>{

static void go()

{ 語句1; }

};

 

template<>

struct my_switch <2>{

static void go()

{ 語句2; }

};

 

調用就是my_switch<>::go();

你也許仍然找不出C++ template版本的switch好處,因爲它要寫更多的代碼。不過你現在靜下來認真的想一想,你會發現當你爲switch插入新的值判斷時,你要返回到switch處,而且還要修改內部的代碼。而用C++ template卻不需要你去關心my_switch到底在哪裏定義的。要添加新的值判斷時,只需要你自己在一個合適的地方添加值判斷的代碼。

 

三、  基於C++ template的數值運算

計算一個常數N的階乘

template<int N>

struct factorial{

    static const int value = N * factorial<N-1>::value;

};

 

template<>

struct factorial<1>{

    static const int value = 1;

};

當這個類模板實例化factorial<N>,就會接着實例化factorial<N-1>,直到實例化fatorial<1>爲止。而你只需要實例化自己想要計算的N就行了,後面的一切全由編譯器包辦。例如我們要輸出10的階乘答案

std::cout<<factorial<10><<std::endl;

 

四、  藉助上面數值計算的方法以產生更實用的代碼

是否考慮過得到指針的原型,比如通過int*,得到int。我們可以寫出下面的代碼

template<typename T>

struct primitive_type{

    typedef T value_type;

};

 

template<typename T>

struct primitive_type<T*>{

    typedef T value_type;

};

 

typedef int* pint;

primitive_type<pint>::value_type obj=5;

std::cout<<obj<<std::endl;

現在可以明確obj不是int*,而是int類型。但是有個缺陷就是但Tint**時卻的不到int,而是得到的int*,這並不是我們想要的答案。現在只需要其實稍微對primitive_type的偏特化版本作下簡單的修改,就可以滿足要求

template<typename T>

struct primitive_type<T*>{

    typedef typename primitive_type<T>::value_type value_type;

};

 

typedef int**** pint;

primitive_type<pint>::value_type obj=5;  這個obj可以確認他是int,而不是int***

 

//The End

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