難度:
<?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-else的template有點大提小做的感覺,呵呵,繼續往下看
二、 將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類型。但是有個缺陷就是但T是int**時卻的不到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