1.問題,最近看項目log模塊,_log模板函數中的一個參數竟然看蒙x了。函數原形是這樣:
template<size_t size>
void _Log(char (&strDest)[size], const char *scetion, const char *key, const char *msg, va_list &parm);
對!就是 char (&strDest)[size]沒有看懂。這個傳進來的是個字符串數組。
2.翻開c++聖經<c++primer>,找到答案。設計模板類型形參中的 非類型形參和數組引用類型形參。
首先,數組作為形參,有引用和非引用兩種形式。一般我們使用非引用形式,也就是將形參定義為數組元素類型的指針,一共有三個等價形式:
1.void func(int *p);
2.void func(int p[]);
3.void func(int p[10]);
其中第三個顯示的表明 調用該函數時,所傳遞的數組最多有10個元素。但是實際上編譯器會忽略為任何數組指定的形參長度,換句話說,第三個函數聲明中的10,其實是被編譯器忽略的。
當我們調用上邊的函數時,傳遞數組名時,數組名會自動轉化為指向數組第一個元素的指針。也就是該指針所存放的是數組第一個元素的地址。 然后形參復制的是這個指針指向的地址。
然后,當數組作為形參,采用引用的方式時,形式是這樣:
1.void func(int (&p)[10]);
當調用此函數時,必須傳遞的是 具有10個int型元素的數組。類似這樣
int a[10] = {};
func(a);
如果這樣 int b[2] = {}; func(b); 是不正確的,因為b不是10個元素。當形參是引用類型時,理解引用的含義很重要。引用就是一個變量的別名,但是終究是該變量自己。
同時,使用引用時,沒有復制的環節,大多時候會節省空間,提升效率。
3.但是,我們可以看出,以上形式的數組的引用型形參,是很不方便的。因為傳遞數組時,存在類型和長度的雙重限制。
那么有沒有一種方法,能夠解決上述問題呢? 既能用到引用的有點,同時又能避免長度帶來的限制?
答案就是采用 1. 中的模板函數以及使用非類型模板形參。
template<size_t size>
void func(int (&p)[size]){ ... }
聖經中講到:模板非類型形參是模板定義內部的常量值,在需要常量表達式的時候,可使用非類型形參指定數組的長度, 當調用 func是,編譯器會從數組的實參計算非類型形參的值,也就是編譯器替我們
計算好了size的值,從而省去我們自己傳遞長度。這樣一來,就可以傳遞數組元素相同的數組了,不必擔心長度。從而避免了2中的缺點
這樣一來:
int a[10], b[2];
func(a);func(b)都可以正確調用,同時size的值為a和b的數組長度。
另外一點需要說明,盡管用了模板的非類型形參,讓我們可以省去數組長度的限制,但是實際上,編譯器會產生兩個func的實例 func<10>, func<2>.
如果此時聲明 int c[10]; func(c); 此時a和c將使用相同的實例。
這基於: 對於模板的非類型形參而言,求值結果形同的表達式將認為是等價的。
因此 a和c調用 func(int (&p)[10]), b調用 func(int (&p)[2]).
4.至此,_log函數中的第一個形參已經弄清--數組的應用型形參。同時利用模板的非類型形參,除去了數組長度的限制。
水平有限,歡迎指正錯誤。