乙個可變引數模板(variadic template)就是乙個接受可變數目引數的函式模板或類模板。
可變數目的引數被稱為引數包(parameter packet)。
存在兩種引數包:模板引數包(template parameter packet),表示0個或多個模板引數;函式引數包(function parameter packet),表示0個或多個函式引數。
採用省略號(…)的形式來指出這是乙個引數包。
在模板引數列表中,class…或typename…指出接下來的引數表示0個或多個型別的列表。乙個型別名後面跟省略號(t…)表示0個或多個給定型別t的非型別引數的列表。在函式引數列表中,如果乙個引數的型別是乙個模板引數包,則此引數也是乙個函式引數包。
eg:
//args 是乙個模板引數包;rest是乙個函式引數包
//args 表示0個或多個模板引數型別
//rest 表示0個或多個函式引數
template
<
typename t,
typename..
. args>
void
foo(
const t &t,
const args&..
. rest)
;
宣告了foo函式是乙個可變引數函式模板,它有乙個名為t的型別引數和乙個名為args的模板引數包。
template
<
typename t,
typename..
. args>
void
foo(
const t &t,
const args&..
. rest)
void
test01()
結果:
編譯器為foo例項化了兩個不同的版本:
void
foo(
const
int&
,const string&
,const
int&
,const
double&)
;void
foo(
const
char[3
]&);
每個例項的t型別都是第乙個實參的型別,剩下的是引數包。
sizeof...
運算子可以用來檢視包中元素個數。
通過遞迴呼叫實現可變引數函式print.
template
<
typename t>
ostream&
print
(ostream &os,
const t &t)
template
<
typename t,
typename..
. args>
ostream&
print
(ostream &os,
const t &t,
const args&..
. rest)
void
test02()
結果:
第乙個版本的print是乙個普通的函式模板,它接受乙個輸出流和乙個t型別,其的功能是輸出t,並返回輸出流的引用。其負責終止遞迴並列印初始呼叫中的最後乙個實參。
第二個版本是乙個可變引數函式模板,它列印繫結到t的實參,並呼叫自身列印引數包中剩下的值。
在每一次呼叫
return
print
(os, rest...
);
時,rest中的第乙個包中的實參被繫結到t,剩下的形成下乙個print呼叫的引數包。
那麼,在呼叫
print
(cout,i,s,
42,d,
'\n'
);
時,會發生如下遞迴呼叫:呼叫t
rest…
print(cout,i,s,42,d,』\n』)
is,42,d,』\n』
print(cout,s,42,d,』\n』)
s42,d,』\n』
print(cout,42,d,』\n』)
42d,』\n』
print(cout,d,』\n』)
d『\n』
print(cout,』\n』) 呼叫普通版本
對於最後一次呼叫,編譯器會選擇更加特化的普通版本。
注意:普通版本和可變引數版本要在同一作用域,否則會無限遞迴。對於乙個引數包,除了獲取其大小以外,唯一能對其進行的操作就是展開(expand)它。當展開乙個包時,我們要提供用於每個擴充套件元素的模式(pattern)。展開乙個包就是將它分解成構成的元素,對每個元素應用模式,獲得展開後的列表。通過在模式右邊放乙個省略號(…)來觸發展開操作。
eg:
template
<
typename t,
typename..
. args>
//展開args
ostream&
print
(ostream &os,
const t &t,
const args&..
. rest)
//展開rest
第乙個展開操作展開模板引數包,為print生成函式引數列表。第二個擴充套件操作出現在對print的呼叫中。此模式為print呼叫生成實參列表。
對args的展開中,編譯器將模式const args& 應用到模板引數包args中的每個元素。因此,此模式的擴充套件結果是乙個逗號分隔的0個或多個型別的列表,每個型別形如const type& 。
例如:
print
(cout,i,s,
42,d,
'\n');
//引數包大小為4
最後4個實參的型別和模式一起確定了未知引數的型別。此呼叫被例項化為:
ostream&
print
(ostream &
,const
int&
,const string&
,const
int&
,const
double&,
const
char&)
;
第二個擴充套件發生在對print的遞迴呼叫中。在此情況下,模式是函式引數包的名字(即rest)。此模式擴充套件出乙個由包中元素組成的、逗號分隔的列表。因此,這個呼叫等價於
print
(os,s,
42,d,
'\n'
);
使用較為複雜的擴充套件模式。
//... print 的兩個版本
此處使用的模式是ossprint(rest),這個模式表示對包中的每乙個元素呼叫ossprint。
注意省略號的位置。是在ossprint(rest)…而不是ossprint(rest…),其原因是ossprint並不接受乙個可變引數包,它只會接受乙個普通型別引數。
《c++ primer 第5版》
C 可變引數模板
c 可變引數模板 flyfish c 98版本不支援 c 11版本以上支援 arguments 是引數包 parameter pack 類 classname 可以接受可變引數個數 template class custom tuple custom tuple c1 custom tuple c2...
c 可變引數模板
可變模板引數函式 1.逗號表示式展開引數包 templatevoid expand const f f,args.args expand auto i 1,2.0,test 2.遞迴函式方式展開 template void printarg t t 終止遞迴 templatevoid process...
可變引數模板
乙個可變引數模板就是乙個接受可變數目引數的模板函式或模板類。可變數目的引數被稱為引數包 parameter packet 存在兩種引數包 模板引數包 template parameter packet 表示零個或多個模板引數 函式引數包 function parameter packet 表示零個或...