C 可變引數模板

2021-10-14 05:38:44 字數 4188 閱讀 9194

乙個可變引數模板(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 表示零個或...