1. 程式人生 > >Item 48:瞭解模板超程式設計

Item 48:瞭解模板超程式設計

Item 48: Be aware of template metaprogramming.

模板超程式設計(Template Metaprogramming,TMP)就是利用模板來編寫那些在編譯時執行的C++程式。 模板元程式(Template Metaprogram)是由C++寫成的,執行在編譯器中的程式。當程式執行結束後,它的輸出仍然會正常地編譯。

C++並不是為模板超程式設計設計的,但自90年代以來,模板超程式設計的用處逐漸地被世人所發現。

  • 模板程式設計提供的很多便利在面向物件程式設計中很難實現;
  • 程式的工作時間從執行期轉移到編譯期,可以更早發現錯誤,執行時更加高效。
  • 在設計模式上,可以基於不同的策略,自動組合而生成具體的設計模式實現。

靜態型別檢查

Item 47中提到了這樣一個std::advance的實現:

template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d) {
  if (typeid(typename std::iterator_traits<IterT>::iterator_category) ==
    typeid(std::random_access_iterator_tag)){
      iter += d;
  }
  ...
}

list<int
>
::iterator it; advance(it, 10);

其實上述程式碼是不能編譯的,設想以下advance< list< int>::iterator, int>中的這條語句:

iter += d;

list< int>::iterator是雙向迭代器,不支援+=運算。雖然上述語句不會執行,但編譯器不知道這一點。 編譯時這條語句仍然會丟擲型別錯誤。

模板超程式設計

TMP後來被證明是圖靈完全的,這意味著TMP可以用來計算任何可計算的問題。你可以宣告變數、執行迴圈、編寫和呼叫函式等等。 但它的使用風格和普通C++完全不同。

我們來看看TMP中如何執行一個迴圈:

template<unsigned n>
struct Factorial{
    enum{ value = n * Factorial<n-1>::value };
};
template<>
struct Factorial<0>{
    enum{ value = 1 };
};

int main(){
    cout<<Factorial<5>::value;
}

這是一個典型的TMP例子,其低位就像是普通程式語言中的”hello world”一樣。

TMP的用途

為了更好地理解TMP的重要性,我們來看看TMP能幹什麼:

  1. 確保量綱正確。在科學計算中,量綱的結合要始終保持正確。比如一定要單位為”m”的變數和單位為”s”的變數相除才能得到一個速度變數(其單位為”m/s”)。 使用TMP時,編譯器可以保證這一點。因為不同的量綱在TMP中會被對映為不同的型別。
  2. 優化矩陣運算。比如矩陣連乘問題,TMP中有一項表示式模板(expression template)的技術,可以在編譯期去除臨時變數和合並迴圈。 可以做到更好的執行時效率。
  3. 自定義設計模式的實現。設計模式往往有多種實現方式,而一項叫基於策略設計(policy-based design)的TMP技術可以幫你建立獨立的設計策略(design choices),而這些設計策略可以以任意方式組合。生成無數的設計模式實現方式。