C++學習 之 模板

C++是一種兩層次語言。

C++的模板設計之初是爲了實現泛型編程,但後來發現模板的能力遠不止泛型編程,C++模板是圖靈完備的,理論上來說C++模板可以執行任何計算任務,但因爲模板是編譯期間計算的,其能力受編譯器實現的限制,因而衍生出模板元編程。

動態代碼

C++執行期間的代碼稱爲動態代碼,動態代碼就不多介紹。

靜態代碼

C++執行編譯計算的代碼稱爲靜態代碼,靜態代碼由模板元編程和預處理的宏組成,預處理的宏也能進行部分編程,因而稱爲宏元編程。
模版元編程舉例:

template<typename T, int i=1>
class someComputing {
public:
    typedef volatile T* retType; // 類型計算
    enum { retValume = i + someComputing<T, i-1>::retValume }; // 數值計算,遞歸
    static void f() { std::cout << "someComputing: i=" << i << '\n'; }
};
template<typename T> // 模板特例,遞歸終止條件
class someComputing<T, 0> {
public:
    enum { retValume = 0 };
};

模版元編程的控制結構:
條件 if 語句:

// 通例爲空,若不匹配特例將報錯,很好的調試手段(這裏是 bool 就無所謂了)
template<bool c, typename Then, typename Else> class IF_ { };
template<typename Then, typename Else>
class IF_<true, Then, Else> { public: typedef Then reType; };
template<typename Then, typename Else>
class IF_<false,Then, Else> { public: typedef Else reType; };

IF_<> 的使用示例

const int len = 4;
typedef
    IF_<sizeof(short)==len, short,
    IF_<sizeof(int)==len, int,
    IF_<sizeof(long)==len, long,
    IF_<sizeof(long long)==len, long long,
    void>::reType>::reType>::reType>::reType
int_my; // 定義一個指定字節數的類型
std::cout << sizeof(int_my) << '\n';

while 語句:

// 隱含要求: Condition 返回值 ret,Statement 有類型 Next
template<template<typename> class Condition, typename Statement>
class WHILE_ {
    template<typename Statement> class STOP { public: typedef Statement reType; };
public:
    typedef typename
        IF_<Condition<Statement>::ret,
        WHILE_<Condition, typename Statement::Next>,
        STOP<Statement>>::reType::reType
    reType;
};

WHILE_<> 的使用示例

// 計算 1^e+2^e+...+n^e
template<int n, int e>
class sum_pow {
    template<int i, int e> class pow_e{ public: enum{ ret=i*pow_e<i,e-1>::ret }; };
    template<int i> class pow_e<i,0>{ public: enum{ ret=1 }; };
    // 計算 i^e,嵌套類使得能夠定義嵌套模板元函數,private 訪問控制隱藏實現細節
    template<int i> class pow{ public: enum{ ret=pow_e<i,e>::ret }; };
    template<typename stat>
    class cond { public: enum{ ret=(stat::ri<=n) }; };
    template<int i, int sum>
    class stat { public: typedef stat<i+1, sum+pow<i>::ret> Next;
                         enum{ ri=i, ret=sum }; };
public:
    enum{ ret = WHILE_<cond, stat<1,0>>::reType::ret };
};

int main() {
    std::cout << sum_pow<10, 2>::ret << '\n';
    std::cin.get(); return 0;
}

借鑑總結

  1. C++ 模板包括函數模板和類模板,模板參數形式有:類型、模板型、非類型(整型、指針);
  2. 模板的特例化分完全特例化和部分特例化,實例將匹配參數集合最小的特例;
  3. 用實例參數替換模板形式參數稱爲實例化,實例化的結果是產生具體類型(類模板)或函數(函數模板),同一模板實參完全等價將產生等價的實例類型或函數;
  4. 模板一般在頭文件中定義,可能被包含多次,編譯和鏈接時會消除等價模板實例;
  5. template、typename、this 關鍵字用來消除歧義,避免編譯錯誤或產生不符預期的結果;
  6. C++11 對模板引入了新特性:“>>”、函數模板也可以有默認參數、變長模板參數、外部模板實例(extern),並棄用 export template;
  7. C++ 模板是圖靈完備的,模板編程是函數編程風格,特點是:沒有可變的存儲、遞歸,以“<>”爲輸入,typedef 或靜態常量爲輸出;
  8. 編譯期數值計算雖然實際意義不大,但可以很好證明 C++ 模板的能力,可以用模板實現類似普通程序中的 if 和 while 語句;
  9. 一個實際應用是循環展開,雖然編譯器可以自動循環展開,但我們可以讓這一切更可控;
  10. C++ 模板編程的兩個問題是:難調試,會產生冗長且難以閱讀的編譯錯誤信息、代碼膨脹(源代碼膨脹、二進制對象文件膨脹),改進的方法是:增加一些檢查代碼,讓編譯器及時報錯,使用特性、策略等讓模板更通用,可能的話合併一些模板實例(如將代碼提出去做成單獨模板);
  11. 表達式模板和向量計算是另一個可加速程序的例子,它們將計算表達式編碼到類型,這是通過模板嵌套參數實現的;
  12. 特性,策略,標籤是模板編程常用技巧,它們可以是模板變得更加通用;
  13. 模板甚至可以獲得類型的內部信息(是否有某個 typedef),這是反射中的內省,C++ 在語言層面對反射支持很少(typeid),這不利於模板元編程;
  14. 可以用遞歸實現僞變長參數模板,C++11 變長參數模板背後的原理也是模板遞歸;
  15. 元容器存儲元信息(如類型)、類型過濾過濾某些類型,它們是元編程的高級特性。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章