這次介紹另一個C++11重要的特性Variadic templates
從printf說起
相信每個寫程式的人,就算沒用過printf,也聽過printf的名字,printf的徒子徒孫大概跟Unix的子孫一樣多。而一般的printf使用方式就類似如此。
1 | int my_printf(const char * format, ...); |
在設計一個通用函數的時候,無法知道後面參數有多少個,因此需要一個支持不定參數的機制。
從上面的程式碼看出,我們支援不定參數的語法就是...
來表示。
而在C語言如何實做這樣的機制,可以參考MSDN上的範例。
Marco也支援不定參數
在C99標準裡,Macro支持不定參數,不過Visual Studio至今不支援C99。
我們可以寫類似這樣的Macro
1 |
在參數列的最後面寫 …,然後就可以用 VA_ARGS 代表 … 所傳入的參數。
如何讓Template支援不定參數
從C++98談起
在實作Command Design Pattern的時候,常常需要把外部函數的參數原封不動的傳遞至內部函數,解決方法大概就像這樣。
1 |
|
這方案的缺點大概有以下幾點
- 可代入的參數數量有限 (雖然可以手動擴充)
- 程式碼難以維護,核心的程式碼不多,但是重複的程式碼很多
- 編譯速度緩慢
- 極度依賴Preprocessor
加上C++11的新特性之後,問題變得更複雜了。
C++11時期
來個最簡單的範例
1 | template <typename... Args> |
在Args左邊出現...
時,表示Args是一個Template type parameter pack,如上面的最後一行,T就是double,而Args就是int, string,除了類別之外,非類別的template paramter也可以這樣使用。如下
1 | template <unsigned ...dims> |
而Function template也可以像Class Template一樣使用不定參數
1 | template <typename ...Args> |
這裡的Args不是Type,args也不是一個value,所以以下的程式碼會出問題
1 | typedef Args MyList; |
而sizeof也跟著Variadic templates而新增新特性,sizeof...
可以印出Args到底有多少個參數
1 | template <typename... Args> |
如何解決之前的問題
用新的特性同時解決perfect forwarding跟Variadic templates
1 | template <typename ...Ts> |
如何抽取單一個型別與參數
透過Template specification來實作
1 | template <typename T> |
還有其他未介紹到的特性,基於所知有限<無法完全說明,可以參考Variadic Templates (Revision 3) Draft跟Variadic Templates are Funadic