(原創) 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++


執行結果

2004310016


recursive由於在run-time執行,所以非常耗內存,TMP(Template MetaProgramming)則是將recursive運算搬到compile-time。

ISO C++


執行結果

2004310016


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行

template <unsigned n>
struct Factorial {
  
enum { value = n * Factorial<n-1>::value };
}
;


我們看到了template <unsigend n>,這允許non-type template parameter,所以可以利用template如一般function那樣傳入參數而非型別,如此才有可能在compile-time做運算。

15行使用了enum hack的方式定義value,大體上相當於

static const int value = n * Factorial<n-1>::value;


 不過TMP習慣都用enum hack方式撰寫。

18行

template<>
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。


執行結果

2004310016


13行

template <unsigned n>
struct Factorial {
  
enum { value = n * Factorial<n-1>::value };
}
;


你一定會問,為什麼在C++/CLI不使用managed class呢?因為若改成

template <unsigned n>
ref struct Factorial {
  
enum { value = n * Factorial<n-1>::value };
}
;


會出現以下錯誤訊息

cannot define unnamed class, struct or union inside of managed type 'Factorial<n>'


也就是說managed class不能使用enum hack!!

夢在天涯 的C++的匿名枚举 中提到,enum hack其實相當於static const int,所以我們試著改用static const int

C++/CLI by static const int


執行結果

2004310016


18行

template <unsigned n>
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

posted on 2007-07-28 19:41  真 OO无双  阅读(4604)  评论(4编辑  收藏  举报

导航