這章介紹基本的 template 技巧,雖然說基本,但是並不是很直接可以想出來的。
Compile Time Assertions
即使不用 template,static/compile time assert 也是 C++ 很常用的工具,但是 standard library 沒有提供。原理是用 template specialization,提供 true 的實作,但是不提供 false 的實作。
template<bool> struct StaticAssertFail;
template<> struct StaticAssertFail<true>{};
#define STATIC_ASSERT(value) StaticAssertFail<value>()
Partial Template Specialization
Class template 可以只給定部份的參數特製化,但是 function template 不能,這直接看語法就懂了。也是很常用的功能。
Local Classes
C++ 允許在 function 定義裡面宣告 local class,就像 local variable 一樣。妙的是,local class 也可以繼承外面的 class,還可以把指標傳出去,就會變成外面無法看的 type。不過 local class 不能作為外面的 template 參數。
Int2Type and Type2Type
用 template 製造新的 type,可以作為 function overloading 區分用,因為製造出來的 type 不像原本的 type 會自動轉換。
template<int N>
struct Int2Type
{
enum{ value = N };
};
template<class T>
struct Type2Type
{
typedef T Type;
};
Type Selection
用 partial template specialization 實作下面的 template class,使得 IS_T == true 的時候,得到type T,否則得到 type U。
template
struct Select
{
typedef T Type;
};
Detecting Convertibility and Inheritance at Compile Time
這是這章裡面最巧妙的部份,使用許多技巧偵測兩個 type 是否可自動轉型,這分成幾個步驟。
- 定義 class template 界面,規定 T 可以轉型成為 U 為 true
- 宣告兩個overload function Test 接受 T 為參數,如果 T 可以自動轉型成為 U,compiler 會選擇第一個 Test()。如果不行,就要選擇第二個 Test()
- 第一個 Test 直接接受參數 U,可自動轉型的情況
- 第二個 Test 接受其他的狀況,而且不能包含第一個 Test 的狀況。這邊比較妙,使用 Test(...) 因為 priority 低,又可以接受所有 type.
- 兩個 Test() 回傳不同 type
- 使用 sizeof() 是 compile time 就可以決定的特性,判斷 sizeof( Test( T() ) ) 的結果。為了用這個特定,兩個 Test() 回傳的 type 必須有不同的 sizeof().
- 因為 sizeof() 裡面不會真正執行,所以兩個 Test() 只需要宣告,不需要真正實作。但 enum exists 是 const expression,所以所有 function 都要是 static.
template <class T, class U>
struct Conversion
{
private:
typedef char Small;
typedef struct{ char c[2]; } Big;
static T _makeT();
static Small _test(U);
static Big _test(...);
public:
enum
{
exists = (sizeof(_test(_makeT())) == sizeof(Small))
};
};
Type Traits
提供 template 在 compile time 偵測 type 的資訊,包括是否為 pointer,是否為 fundamental type,最適合用來傳參數的 type 等。這裡面大部分都是用 template 列舉,就比較可以想得出來。
No comments:
Post a Comment