在C++11新標(biāo)準(zhǔn)中,可變模板參數(shù)可以算是一個(gè)非常重要也是非常強(qiáng)大的特性,相對(duì)于普通的模板,它提供了更高程度的泛化。
可變模板參數(shù)涉及2個(gè)方面:參數(shù)類型可變;參數(shù)個(gè)數(shù)可變。
1.可變模板參數(shù)的基本語法
首先回顧一下模板的基本使用方法,下圖是模板函數(shù)和模板類的簡單使用方式。

對(duì)于可變模板參數(shù),個(gè)人理解是在原來模板的基礎(chǔ)上增加了“...”關(guān)鍵字,當(dāng)然,“...”位置不同,表示的含義也不同。
下面以一個(gè)可以打印任意個(gè)數(shù)任意類型(可以打印的類型)函數(shù)介紹“...”的使用方法

(1)模板參數(shù)包
第一個(gè)class...Types,寫在template 的<>中,因此在使用模板函數(shù)時(shí)可以指定任意類型(在main函數(shù)中的Print調(diào)用)
(2)函數(shù)參數(shù)類型包(擴(kuò)展包)
第二個(gè)Types...args,用在Print函數(shù)的形參中,表示任意類型的任意參數(shù)
(3)函數(shù)參數(shù)包
第三個(gè)args...,用在Print函數(shù)的遞歸調(diào)用中,實(shí)際上是實(shí)參
(4)其他情況
若想要獲得參數(shù)包中的參數(shù)數(shù)量,需要使用sizeof...(args)來獲得
PS:上面看到了...的使用情況:在形參左側(cè)、參數(shù)右側(cè)
1)省略號(hào)出現(xiàn)形參名字左側(cè),聲明了一個(gè)參數(shù)包(parameter pack)。使用這個(gè)參數(shù)包,可以綁定0個(gè)或多個(gè)模板實(shí)參給這個(gè)可變模板形參參數(shù)包。參數(shù)包也可以用于非類型的模板參數(shù)(也就是參數(shù)數(shù)量不固定,但是每個(gè)參數(shù)的類型是一樣的,即將Types args 替換成 int args)。
2)省略號(hào)出現(xiàn)包含參數(shù)包的表達(dá)式的右側(cè),則把這個(gè)參數(shù)包解開為一組實(shí)參(也就是args... = arg1, arg2, arg3,...)。
2. 可變模板參數(shù)的應(yīng)用
(1)可變參數(shù)模板函數(shù)展開參數(shù)包
???? 1)遞歸函數(shù)方式展開

上面是求和函數(shù)的遞歸調(diào)用,以遞歸的方式展開一般會(huì)將整個(gè)包拆解成第一個(gè)參數(shù)和其他所有參數(shù),逐層拆解,最后需要具體化出一個(gè)邊界條件。

??? 上述代碼是使用可變模板參數(shù)實(shí)現(xiàn)C語言中的printf()函數(shù),采用了遞歸函數(shù)展開的方式。
????? 2)逗號(hào)表達(dá)式展開

沒有簡單機(jī)制去在可變模板參數(shù)的每個(gè)單獨(dú)值上迭代。幾乎沒有什么方式可以把參數(shù)包直接轉(zhuǎn)為單獨(dú)實(shí)參來使用。因此,想要將模板參數(shù)包拆分,需要借助print函數(shù)(該函數(shù)每次只能接受一個(gè)參數(shù))
之前的帖子說:{(printarg(args), 0)...}將會(huì)展開成((printarg(arg1),0), (printarg(arg2),0), (printarg(arg3),0), etc... ),最終arr[]數(shù)組中存放了4個(gè)0,在我的試驗(yàn)下發(fā)現(xiàn),可以寫成
???????????????????????????????? int arr[] = {(args)...};
最終arr[]數(shù)組中就可以存放1,2,3,4了。
(2)可變模版參數(shù)類展開參數(shù)包
???? 1)可變參數(shù)模板用于遞歸繼承
在c++11的STL中引入了一個(gè)新的容器tuple,下面代碼將tuple的源碼改造,展示tuple是如何通過遞歸繼承來實(shí)現(xiàn)存放不同類型的數(shù)據(jù)的。

可以看出類的遞歸繼承與函數(shù)的遞歸調(diào)用原理相似,都是將一組參數(shù)包分解成首個(gè)參數(shù)和其他所有參數(shù),最終需要一個(gè)遞歸的結(jié)束條件。下圖是某個(gè)tuple<>的繼承關(guān)系圖。

??? 2)可變參數(shù)模板用于遞歸組合
在類中使用(復(fù)用)另外一個(gè)類,可以通過繼承的方式,也可以采用組合的方式。同樣韓式以Tuple為例,使用遞歸組合的方式來實(shí)現(xiàn),代碼如下。

下圖是每個(gè)類之間的關(guān)系圖,與遞歸繼承類似,每個(gè)模板類都展開,不同的是類之間的關(guān)系是采用組合的方式。

???? 3)模板遞歸和特化方式展開參數(shù)包
在類的遞歸繼承中,模板參數(shù)的類型和數(shù)量都是可變的,下面的例子是針對(duì)類型相同、個(gè)數(shù)不同的情況,如何寫代碼。

3.總結(jié)
可變模板參數(shù)是C++11新標(biāo)準(zhǔn)中很有意思的特性,同樣也具有很強(qiáng)大的功能。使用可變模版參數(shù)的關(guān)鍵是如何展開參數(shù)包,這一過程中包含了泛化、遞歸等思想。使用可變模板參數(shù)可以完成更加“萬能”的函數(shù)、類,當(dāng)然個(gè)人水平遠(yuǎn)達(dá)不到能夠完全掌握該特性的程度,以后會(huì)在學(xué)習(xí)中補(bǔ)充。
參考:
侯捷老師的c++11新特性視頻
https://blog.csdn.net/dolphin98629/article/details/95038039
https://blog.csdn.net/tony__lin/article/details/84677316