2012-04-06 156 views
19

例如,我已經知道stdarg.h函數具有帶C++變量參數的函數,如here所討論的。 我也知道C++ 11標準具有可變參數模板here一個具有可變參數類型的可變參數的函數,C++ 11的方法

但是在上述兩個方案中,我們都不知道(也不能強制)編譯時afaik中的參數類型。我在尋找的是將已知類型的可變參數傳遞給函數。我認爲這是可以做到,因爲我讀到它here

可變參數模板,也可用於創建帶可變數量的參數功能,往往是更好的選擇,因爲他們不強加限制參數類型,不執行整數和浮點升級,並且是類型安全的。

可能嗎?如果是的話,我該怎麼做?

回答

30

用可變參數模板編寫函數是很簡單的,它接受任意數量的參數。與一般模式唯一的區別在於,具體類型被用作第一個參數(頭部) - 而不是模板參數。以下示例顯示了一個函數foobar,它接受任意數量的字符串。

// used for end of recursion - and for the empty arguments list 
void foobar() { } 

template <typename ...Tail> 
void foobar(const std::string& head, Tail&&... tail) 
{ 
    // do something with head 
    std::cout << head << '\n'; 
    // call foobar recursively with remaining arguments 
    foobar(std::forward<Tail>(tail)...); 
} 

foobar("Hello", "World", "..."); 

個人而言,我更喜歡使用std::initializer_list而不是可變參數模板。由於可變模板更復雜,需要額外的經驗。使用std::initializer_list與普通函數時

void foobar(std::initializer_list<std::string> values) 
{ 
    for (auto& value : values) { 
     // do something with value 
     std::cout << value << '\n'; 
    } 
} 

foobar({ "Hello", "World", "...", }); 

不幸的是,需要額外花括號:隨着std::initializer_list,它可能是這樣的。如果使用新的初始化程序語法,則它們不是構造函數所必需的。

編輯:根據反饋重寫了答案。特別是我改變了兩個解決方案/例子的順序。

+1

我認爲這全是關於我的誤解。我知道第二種方式,但我一直認爲參數類型無法控制。這不是真的。因爲該函數接受一個已知類型的第一個參數(字符串在這裏),所以它被隱含地強制擁有該類型的參數。謝謝。 – melmi 2012-04-06 16:39:00

+2

您可能需要先移動第二個代碼框。這是一個非常好的解決方案,而'initializer_list'版本不是。我打算用SFINAE等發佈一個大型複雜的東西,但這更合理。 – 2012-04-06 16:43:29

+0

@nosid通過在std :: initializer_list版本週圍創建一個可變模板包裝器,你可以避免使用大括號,如果你混合使用std :: initializer_list和variadic模板方法,就像這樣:[see coliru](http: //coliru.stacked-crooked.com/a/4baef67192a0310c)。 – 2016-05-31 02:37:32

2

如果變量參數都是一種類型,您可以更改函數簽名以獲取這些類型的數組,而不是使用'...'。

+0

一種類型的數組需要迭代,而可變參數函數的使用提供了編譯時內聯機制。你可能會說在數組上循環並不是那麼花時間,但在另一個多循環中考慮它。 – melmi 2012-04-06 14:10:21

相關問題