所謂可變參數指的是函數的參數個數可變,參數類型不定的函數。
省略符表達可變參數
函數可以用省略符形參”…”表示不定參數部分,省略符形參只能出現在形參列表的最後一個位置,這是從C語言繼承過來的表達方式。它的形式如下:
void foo(parm_list, ...);
int printf(const char* format, ...);
下面是< cstdarg >頭文件中的幾個宏定義
舉個例子:
這種方式有什麼問題呢?
1. 函數本身並不知道傳進來參數個數,多傳一個參數,或者少傳一個參數,在編譯期是檢測不到這個問題的,這就可能會導致未定義的錯誤。
2. 函數不知道傳進來的參數類型。如果函數類型與預期不符,在編譯期也無法檢測,可能導致未定義錯誤。
3. 對於可變長參數,只能用__cdecl調用約定,因為只有調用者才知道傳進來幾個參數,所以也只有調用者才能維持棧平衡。如果是__stdcall,那麼函數需要負責棧平衡,可是函數本身根本不知道有幾個參數,函數調用結束後,根本不知道需要將幾個參數pop out。
initializer_list的方式
這是在C++11中新增的方法,如果所有的實參類型相同,就可以用C++11提供的標準庫類型initializer_list。
initializer_list是一種模板類型。可以看看initializer_list提供的一些操作:
如果想給initializer_list形參傳遞一個實參的序列,必須把序列放在一對花括號內:
可變參數模板
可變參數模板(variadic template)就是一個接受可變數目參數的模板函數或模板類。使用時既不需要知道要處理的實參數目也不知道實參的數據類型。它的形式如下:
其中Args是一個模板參數包;rest是一個函數參數包。
可變參數函數模板通常是遞歸的。第一步調用處理包中的第一個實參,然後用剩餘的實參調用自身。為了終止遞歸,我們還需要定義一個非可變參數的函數模板:
變長模板的優點:
1. 參數個數。對於模板來說,在編譯器模板推導的時候,就已經知道參數的個數了。
2.參數類型。在模板推導的時候模板函數的參數類型已經確定。
3. 既然編譯的時候就知道參數個數和參數類型,那麼調用約定也就沒有限制了。
閱讀更多 半杯茶的小酒杯 的文章