C++ Template of template

template 在 C 裡面,算是一個很重要、也很實用的概念。它可以用同樣的程式、來處理不同類型的資料,大幅簡化程式碼的重複性。

而這一篇,算是來簡單紀錄一下,所謂的「template of template」的玩法吧~主要的參考資料,是《Templates of templates》這篇文章。也請注意,這篇只是 Heresy 自己簡單的紀錄,寫得不算很嚴謹。

首先,一般的 template 寫法,可能會像是下面這樣:

template<typename DType>
class CData
{
public:
    std::vector<DType>    mContent;
};

在上面的類別 CData 裡,是用一個 std::vector 來儲存資料,而裡面的型別則是 DType;使用的時候,基本上會是:

CData<int> x;

但是,如果希望可以讓使用者決定要用哪種 STL 容器(container)時該怎麼辦呢?比較直覺的方法,就是寫成:

template<typename DType, typename TContainer >
class CData
{
public:
    TContainer<DType>    mContent;
};

然後在要使用的時候,寫成:

CData<int,std::vector> x;

也就是把 std::vector 的部分,也用 template 的方法來寫。但是很遺憾,這樣的語法是有問題的。


而比較簡單的修改,應該是改成:

template<typename TContainer >
class CData
{
public:
    TContainer    mContent;
};

這樣寫的話,使用時則是會像下面這樣:

CData< std::vector<int> > x;

但是這樣的缺點,就是把資料型別和容器的型別綁在一起了,其實有的時候可能不是那麼地實用。


而如果要把資料型別和容器的類別切割開的話,則可以寫成:

template<    typename DType,
            template<typename T> class TContainer >
class CData
{
public:
    TContainer<DType>    mContent;
};

在這邊,就是很明確地告訴編譯器,TContainer 是一個 template 的類別,而他有一個 template 的參數。這樣一來,就可以任意地套用符合形式的容器了~

不過,如果是要使用 STL 的 vector 的話,由於他實際上有兩個 template 參數(參考),所以直接拿來用會因為 template 參數不相同、而有編譯階段的錯誤;如果要用的話,則是需要再封包一次才行,封包方法大致上可以寫成:

template<typename T>
class CVector : public std::vector<T>
{};

實際使用時是:

CData<int, CVector> x;

而對於其他 STL 的容器、或是自己定義的資料類別,基本上也都是可以用類似的方法來操作的。


為什麼會跑來看這個?其實 Heresy 主要是把這個用在 callable object 上,也就是想用 template 來展開函式。簡單講,就是想下類似下面架構的程式:

#include <iostream>

template<template<typename T> class TFunc>
void FuncTemp(int iMode)
{
    if (iMode == 0 )
    {
        TFunc<int>()();
    }
    else if ( iMode == 1 )
    {
        TFunc<float>()();
    }
}

template<typename T>
class CFunc1
{
public:
    void operator()(){
    }
};

template<typename T>
class CFunc2
{
public:
    void operator()(){
    }
};

int main()
{
    FuncTemp<CFunc1>(1);
    FuncTemp<CFunc2>(0);
}

本來 CFunc1CFunc2 都不是想寫成 class、而是想寫成 template function,但是那樣寫是不合法的,所以只能寫成類別。而後來也因為這樣寫太繁瑣了,還是放棄了…

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。