C++模板元編程 入門簡介


最近一直在看STL和Boost,源碼里邊好多涉及到模板元編程技術,簡單了解一下,備忘(Boost Python中的涉及模板元的部分重點關注一下)。

范例引入

// 主模板
template<int N>
struct Fib
{
    enum { Result = Fib<N-1>::Result + Fib<N-2>::Result };
};

// 完全特化版
template <>
struct Fib<1>
{
    enum { Result = 1 };
};


// 完全特化版
template <>
struct Fib<0>
{
    enum { Result = 0 };
};

int main()
{
    int i = Fib<10>::Result;
    // std::cout << i << std::endl;
} 

 

主要思想

利用模板特化機制實現編譯期條件選擇結構,利用遞歸模板實現編譯期循環結構,模板元程序則由編譯器在編譯期解釋執行。

優劣及適用情況

通過將計算從運行期轉移至編譯期,在結果程序啟動之前做盡可能多的工作,最終獲得速度更快的程序。也就是說模板元編程的優勢在於:

  1.以編譯耗時為代價換來卓越的運行期性能(一般用於為性能要求嚴格的數值計算換取更高的性能)。通常來說,一個有意義的程序的運行次數(或服役時間)總是遠遠超過編譯次數(或編譯時間)。

  2.提供編譯期類型計算,通常這才是模板元編程大放異彩的地方。

模板元編程技術並非都是優點:

  1.代碼可讀性差,以類模板的方式描述算法也許有點抽象。

  2.調試困難,元程序執行於編譯期,沒有用於單步跟蹤元程序執行的調試器(用於設置斷點、察看數據等)。程序員可做的只能是等待編譯過程失敗,然后人工破譯編譯器傾瀉到屏幕上的錯誤信息。

  3.編譯時間長,通常帶有模板元程序的程序生成的代碼尺寸要比普通程序的大,

  4.可移植性較差,對於模板元編程使用的高級模板特性,不同的編譯器的支持度不同。

總結:

模板元編程技術不適用普通程序員的日常應用,它常常會做為類庫開發的提供技術支持,為常規模板代碼的內核的關鍵算法實現更好的性能或者編譯期類型計算。模板元程序幾乎總是應該與常規代碼結合使用被封裝在一個程序庫的內部。對於庫的用戶來說,它應該是透明的。

工程應用實例

1. Blitz++:由於模板元編程最先是因為數值計算而被發現的,因此早期的研究工作主要集中於數值計算方面,Blitz++庫利用模板將運行期計算轉移至編譯期的庫,主要提供了對向量、矩陣等進行處理的線性代數計算。

2.Loki:將模板元編程在類型計算方面的威力應用於設計模式領域,利用元編程(以及其他一些重要的設計技術)實現了一些常見的設計模式之泛型版本。Loki庫中的Abstract Factory泛型模式即借助於這種機制實現在不損失類型安全性的前提下降低對類型的靜態依賴性。

3.Boost:元編程庫目前主要包含MPL、Type Traits和Static Assert等庫。 Static Assert和Type Traits用作MPL的基礎。Boost Type Traits庫包含一系列traits類,用於萃取C++類型特征。另外還包含了一些轉換traits(例如移除一個類型的const修飾符等)。Boost Static Assert庫用於編譯期斷言,如果評估的表達式編譯時計算結果為true,則代碼可以通過編譯,否則編譯報錯。

技術細節

模板元編程使用靜態C++語言成分,編程風格類似於函數式編程,在模板元編程中,主要操作整型(包括布爾類型、字符類型、整數類型)常量和類型,不可以使用變量、賦值語句和迭代結構等。被操縱的實體也稱為元數據(Metadata),所有元數據均可作為模板參數。

由於在模板元編程中不可以使用變量,我們只能使用typedef名字和整型常量。它們分別采用一個類型和整數值進行初始化,之后不能再賦予新的類型或數值。如果需要新的類型或數值,必須引入新的typedef名字或常量。

其它范例

 

View Code
// 僅聲明
struct Nil;

// 主模板
template <typename T>
struct IsPointer
{
    enum { Result = false };
    typedef Nil ValueType;
};

// 局部特化
template <typename T>
struct IsPointer<T*>
{
    enum { Result = true };
    typedef T ValueType;
};

// 示例
int main()
{
    cout << IsPointer<int*>::Result << endl;
    cout << IsPointer<int>::Result << endl;
    IsPointer<int*>::ValueType i = 1;
    //IsPointer<int>::ValueType j = 1;  
    // 錯誤:使用未定義的類型Nil
}
View Code
//主模板
template<bool>
struct StaticAssert;

// 完全特化
template<> 
struct StaticAssert<true>
{};

// 輔助宏
#define STATIC_ASSERT(exp)\
{ StaticAssert<((exp) != 0)> StaticAssertFailed; }

int main()
{
    STATIC_ASSERT(0>1);
}


 

References:

http://club.topsage.com/thread-421469-1-1.html

http://wenku.baidu.com/view/c769720df78a6529647d539d.html

Blitz++: http://www.oonumerics.org/blitz .
Loki :http://sourceforge.net/projects/loki-lib

Boost:http://www.boost.org/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM