在 C 語言中實現模板函數的方法:
各種用 C 語言實現的模板可能在使用形式上有所不同。
現以一個求和函數 Sum 為例,用 C++ Template 可寫如下:
template<class T, class R> R Sum(const T *array, int n)
{
R sum = 0;
for (int i = 0 ; i < n ; ++i)
sum += i;
return sum;
}
如果不是內建類型,該模板隱式地需要 有R R::operator+=(T)運算子可用。
1.
使用函數指標作為 Functor 替換者
Typedef struct tagAddClass
{
Void (*add)(char* r1, const char* r2);
Int elemSize;
Char sum[MAX_ELEM_SIZE];
} AddClass;
void Sum(AddClass* self, const char* array, int n)
{
for (int i = 0 ; i < n ; ++i)
self->add(self->sum, array + i*self->elemSize);
}
使用時:
…..
Void AddInt(char* r1, const char* r2)
{
*(long*)r1 += *(int*)r2;
}
AddClass addClass = {AddInt, 2, 0 };
Int array[100];
Read(array);
Sum(&addClass, array, 100);
…..
2.
用宏作為Functor的替換者
#define GenSumFun(SumFunName, Add, RetType, ElemType) /
RetType SumFunName (const ElemType *array, int n) /
{ /
RetType sum = 0; /
for (int i = 0 ; i < n ; ++i) /
Add(sum, i); /
return sum; /
}
使用時:
#define AddInt(x, y) ((x) += (y))
GenSumFun(SumInt, AddInt, long, int)
…..
Int array[100];
Read(array);
Long sum = SumInt(array, 100);
…..
3.
所有可替換參數均為宏
至少需要一個額外的檔案(實現檔案)為 impsum.c
/* impsum.c */
RetType FunName(const ElemType *array, int n)
{
RetType sum = 0;
for (int i = 0 ; i < n ; ++i)
Add(sum, i);
return sum;
}
使用時:
#undef RetType
#undef FunName
#undef ElemType
#undef Add
#define AddInt(x, y) ((x) += (y))
#define RetType long
#define FunName SumInt
#define ElemType int
#define Add AddInt
#include impsum.c
…..
Int array[100];
Read(array);
Long sum = SumInt(array, 100);
…..
4.
總結:
第一種方法,易於跟蹤調試,但是效率低下,適用於對可變函數(函數指標)的效率要求不高,但程式出錯的可能性較大(複雜),模板函數(Sum)本身很複雜,模板參數也比較複雜(add)的場合。
第二種方法,效率高,但很難跟蹤調試,在模板函數和模板參數本身都很複雜的時候更是如此。
第三種方法,是我最近幾天才想出的,我認為是最好的,在模板參數(Add)比較複雜時可以用函數(第二種也可以如此),簡單時可以用宏,並且,易於調試。在模板函數本身很複雜,而模板參數比較簡單時更為優越。但是,可能有點繁瑣。
一般情況下,沒有必要做如此勞心的工作,一切交給編譯器去做就行了。但是本人在開發一個檔案系統時,由於是基於一種少見的平台,沒有可用的C++編譯器,有幾個函數,除了其中的類型不同(uint16和uint32),和幾個可參數化的宏不同,其它地方完全相同,而函數本身很複雜(兩百多行代碼)。Copy出幾個完全類似的函數副本,維護起來特別煩人。非常需要如此的編程模式,故此,分享出來,大家共同探討。