Monday, March 10, 2014

Techniques, Ch 2, Modern C++ Design

這章介紹基本的 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 是否可自動轉型,這分成幾個步驟。

  1. 定義 class template 界面,規定 T 可以轉型成為 U 為 true
  2. 宣告兩個overload function Test 接受 T 為參數,如果 T 可以自動轉型成為 U,compiler 會選擇第一個 Test()。如果不行,就要選擇第二個 Test()
  3. 第一個 Test 直接接受參數 U,可自動轉型的情況
  4. 第二個 Test 接受其他的狀況,而且不能包含第一個 Test 的狀況。這邊比較妙,使用 Test(...) 因為 priority 低,又可以接受所有 type.
  5. 兩個 Test() 回傳不同 type
  6. 使用 sizeof() 是 compile time 就可以決定的特性,判斷 sizeof( Test( T() ) ) 的結果。為了用這個特定,兩個 Test() 回傳的 type 必須有不同的 sizeof().
  7. 因為 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: