用 C++ Template 建表

(兩年前寫的東西,當時寫在 bbs 上沒公開,最近有空稍微整理一下。)

C++ TMP 可以利用 compile-time 計算一些東西, 凡是 static 資訊都可以算出來, 但如果要 runtime 到才存取呢?想了一個下午, 比較接近的方式是在 class template 裡頭放個 static array,  並且呼叫 value<N>::result 將資料填入表內。 Continue reading

Template 版的 n 維陣列

最簡單的作法, 假設每一維度僅有 10 個元素,
以下能夠宣告在編譯其中任意維度的整數陣列:

template<int DIM>
class Array{
public:
Array<DIM-1> Data[10];
Array<DIM-1>& operator[](int i){
return Data[i];
}
};


template<>
class Array<1>{
public:
int Data[10];
int& operator[](int i){
return Data[i];
}
};

將 [] 這個 operator 重載的主要理由, 是要將這個版本的多維陣列,
當作我們所習慣的用法, 不然 a[i][j] 就要變成 a.Data[i].Data[j] 。

宣告一個三維陣列很簡單, 只有

Array<3> array;

使用上也是 array[i][j][k] 存取, 注意第一個 array[i] 是一個 Array<2>。
比起原本二維陣列的宣告方式, 有沒有漂亮多了呢?XD
要拿掉 10 個元素的限制也很簡單, 只要再修改 class constructor, 也沒什麼問題,
覺得太麻煩就改用 boost 函式庫提供的吧。

補上一個更噁心的 …

template<typename T,
int DIM = 2,
template <typename ELEM, typename = std::allocator<ELEM> >
class CONT = std::deque >
class Array : public CONT< Array<T, DIM-1, CONT> >{};


template<typename T,
template <typename ELEM, typename = std::allocator<ELEM> >
class CONT>
class Array<T, 1, CONT> : public CONT<T> {};

基本上就是 template templete parameters 加上 CRTP 的技術 @”@
要怎麼用呢?

Array<int> array; // 等價於 std::deque< std::deque< int > >
Array<double, 3, std::vector> // 等價 std::vector< std::vector< std::vector<double> > >

Promotion Trait

泛型程式真是恐怖的技巧 @”@

先來講 Promotion Traits。用過 template 的人大概都覺得只是能夠對任意型別產生對應的函式跟物件, 僅此而已。但若需要判斷兩個型別中, 該用哪一個的時候, 就會變得很麻煩, 需要人工處理, 例如:

template<typenmae T>
T const& max(T const& x, T const& y)
{
return x > y ? x : y;
}

會回傳兩個數值之間較大的一個, 而且是任意型別都可以通吃, 但只限定於型別相同的, 也就是說

max(100, 3)     // 合法, 回傳 100
max(100, 3.0)   // 非法, 無法編譯

雖然看起來非常明顯的是, max(100, 3.0) 的結果應該是 100, 卻需要改用以下方式 work around 而不是依照一般的 coercion 的規則:

max<float>(100, 3.0)
max<int>(100, 3.0)

將指定 max 特化為 float 或是 int 版本的函式。
這倒令人有點喪氣, 似乎沒想像中的方便, 但事實上也不盡然如此 … Continue reading