(原創) Template Metaprogramming系列[1] : 使用遞迴/递归(Recursive) (C/C++) (.NET) (C++/CLI) (template) (TMP)
Abstract
遞迴/递归(recursive)優點是代碼精簡,尤其若算法牽涉到前後相關,如n! = n * (n-1) * (n-2)...* 2 * 1,不用recursive很難寫,但recursive的缺點會大量消耗電腦內存,若使用TMP(Template Metaprogramming),則可解決此缺點。
Introduction
一個典型的recursive,求n!,若用傳統recursive寫法如下
ISO C++
執行結果
recursive由於在run-time執行,所以非常耗內存,TMP(Template MetaProgramming)則是將recursive運算搬到compile-time。
ISO C++
執行結果
C++ template原本並不是為TMP而設計,但因為一些特性而造就了TMP:
1.ISO C++的template是compile-time泛型,所以能將運算搬到compile-time解決以節省內存。(.NET generics是run-time泛型,所以對於節省內存無幫助)。
2.ISO C++允許non-type template parameter,如template<int i>,所以可以如function般傳入一般參數,借以將運算搬到compile-time。(.NET generics不允許non-type template parameter)。
3.ISO C++允許template特化(template specialization),recursive的終止條件可利用特化完成。(.NET generics不允許generics特化)。
13行
struct Factorial {
enum { value = n * Factorial<n-1>::value };
};
我們看到了template <unsigend n>,這允許non-type template parameter,所以可以利用template如一般function那樣傳入參數而非型別,如此才有可能在compile-time做運算。
15行使用了enum hack的方式定義value,大體上相當於
不過TMP習慣都用enum hack方式撰寫。
18行
struct Factorial<0> {
enum { value = 1 };
};
運用了template特化,定義recursive的終止條件。
在.NET平台是否可用TMP呢?.NET generics由於缺乏TMP所需的特性,所以C#、VB皆無法使用TMP,不過由於C++/CLI仍然支援template,所以C++/CLI是.NET平台唯一可以使用TMP的語言。
C++/CLI by enum hack
由於TMP慣用enum hack,所以繼續在C++/CLI使用enum hack。
執行結果
13行
struct Factorial {
enum { value = n * Factorial<n-1>::value };
};
你一定會問,為什麼在C++/CLI不使用managed class呢?因為若改成
ref struct Factorial {
enum { value = n * Factorial<n-1>::value };
};
會出現以下錯誤訊息
也就是說managed class不能使用enum hack!!
在夢在天涯 的C++的匿名枚举 中提到,enum hack其實相當於static const int,所以我們試著改用static const int
C++/CLI by static const int
執行結果
18行
ref struct Factorial {
static const int value = n * Factorial<n-1>::value;
};
如此就可以用managed class了。
Conclusion
TMP的優點:
1.可以有較小的exe。
本例求n!,使用recursive寫法,exe檔為6656 bytes,若用TMP寫法,exe檔為6144 bytes。(VC8)
2.執行速度較快。
因為TMP在compile-time已經解決了。
3.較少的內存要求。
因為TMP在compile-time已經計算完畢,不需在run-time耗費大量內存計算。
TMP的缺點:
1.compile時間變長了。
因為運算從run-time搬到compile-time了。
2.語法不直觀。
又是一個paradigm shift,沒TMP概念的人,很難知道你在寫什麼。
3.工具支援還不夠。
如debug支援,設立中斷點..等。
所以TMP的特性,頗適合嵌入式系統開發,因為嵌入式通常只有幾MB甚至幾KB的rom,且CPU和內存條件也遠比PC差,正好可發揮TMP所長。
Reference
夢在天涯 的C++的匿名枚举
Scott Meyers, Effective C++ 3/e Item 48, Addison Wesley, 2005