C++11新特性之變長(zhǎng)參數(shù)模板詳解
C++11 變長(zhǎng)參數(shù)模板
在C++11之前,無(wú)論是類(lèi)模板 還是函數(shù)模板,都只能按其指定的樣子,接受一組固定數(shù)量的模板參數(shù);
這已經(jīng)大大提升了代碼的復(fù)用!
在C++11之后,加入了新的表示方 法,允許任意個(gè)數(shù)、任意類(lèi)別的模板參數(shù),同時(shí)也不需要在定義時(shí)將參數(shù)的個(gè)數(shù)固定。更加像”黑魔法“了。
template<typename... Ts> class Magic;
模板類(lèi) Magic 的對(duì)象,能夠接受不受限制個(gè)數(shù)的 typename 作為模板的形式參數(shù),例如下面的定義:
class Magic<int, std::vector<int>, std::map<std::string, std::vector<int>>> darkMagic;
既然是任意形式,所以個(gè)數(shù)為 0 的模板參數(shù)也是可以的:class Magic<> nothing;。 如果不希望產(chǎn)生的模板參數(shù)個(gè)數(shù)為 0,可以手動(dòng)的定義至少一個(gè)模板參數(shù):
template<typename Require, typename... Args> class Magic;
變長(zhǎng)函數(shù)參數(shù)包
除了在模板參數(shù)中能使用 ... 表示不定長(zhǎng)模板參數(shù)外,函數(shù)參數(shù)也使用同樣的表示法代表不定長(zhǎng)參數(shù)。
傳統(tǒng) C 中的 printf 函數(shù),雖然也能達(dá)成不定個(gè)數(shù) 的形參的調(diào)用,但其并非類(lèi)別安全。而 C++11 除了能定義類(lèi)別安全的變長(zhǎng)參數(shù)函數(shù)外,還可以使類(lèi)似 printf 的函數(shù)能自然地處理非自帶類(lèi)別的對(duì)象。除了在模板參數(shù)中能使用 ... 表示不定長(zhǎng)模板參數(shù)外, 函數(shù)參數(shù)也使用同樣的表示法代表不定長(zhǎng)參數(shù),這也就為我們簡(jiǎn)單編寫(xiě)變長(zhǎng)參數(shù)函數(shù)提供了便捷的手段, 例如:
template<typename... Args> void printf(const std::string &str, Args... args);
其中,Args 與 args 分別代表模板與函數(shù)的變長(zhǎng)參數(shù)集合, 稱之為參數(shù)包 (parameter pack)。參數(shù)包必須要和運(yùn)算符"..."搭配使用。
如何解參數(shù)包
長(zhǎng)參數(shù)模板中,變長(zhǎng)參數(shù)包無(wú)法如同一般參數(shù)在類(lèi)或函數(shù)中使用;這個(gè)很好理解!
因?yàn)樵跅V?,我們需要先知道函?shù)有多少個(gè)參數(shù),才可以入棧,但是我們不知道變長(zhǎng)參數(shù)有多長(zhǎng),所以需要特殊手法!
sizeof()獲得函數(shù)參數(shù)個(gè)數(shù)
首先,我們可以使用 sizeof... 來(lái)計(jì)算參數(shù)的個(gè)數(shù),:
template<typename... Ts> void magic(Ts... args) { std::cout << sizeof...(args) << std::endl; }
遞歸模板函數(shù)
遞歸去獲得所有參數(shù),是非常容易想到的方法,這種方法不斷遞歸地向函數(shù)傳遞模板參數(shù),進(jìn)而達(dá)到遞歸遍歷所有模板參數(shù)的目的。
printf 會(huì)不斷地遞歸調(diào)用自身:函數(shù)參數(shù)包 args... 在調(diào)用時(shí), 會(huì)被模板類(lèi)別匹配分離為 T value和 Args... args。 直到 args... 變?yōu)榭諈?shù),則會(huì)與簡(jiǎn)單的 printf(const char *s) 形成匹配,退出遞歸。
//遞歸模板函數(shù) template<typename T0> void printf1(T0 value) { std::cout << value << std::endl; } template<typename T, typename... Ts> void printf1(T value, Ts... args) { std::cout << value << std::endl; printf1(args...); } int RecursiveTemplateFunc() { printf1(1, 2, "123", 1.1); return 0; }
變參模板展開(kāi)
上面的遞歸很容易理解,但是比較繁瑣,那么還有沒(méi)有什么好方法呢?
在 C++17 中增加了變參模板展開(kāi)的支持,于是你可以在一個(gè)函數(shù)中完 成 printf 的編寫(xiě):
//變參模板展開(kāi) template<typename T0, typename... T> void printf2(T0 t0, T... t) { std::cout << t0 << std::endl; if constexpr (sizeof...(t) > 0) printf2(t...); }
結(jié)論
模板作為C++中的”黑魔法“般的武器,學(xué)起來(lái)比較難,但當(dāng)掌握后,確實(shí)非常高級(jí),變長(zhǎng)參數(shù)模板對(duì)我們寫(xiě)模板有很大的幫助!
本文的代碼地址: Modern_Cpp_Practice.
到此這篇關(guān)于C++11新特性之變長(zhǎng)參數(shù)模板詳解的文章就介紹到這了,更多相關(guān)C++11 變長(zhǎng)參數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Qt數(shù)據(jù)庫(kù)應(yīng)用之實(shí)現(xiàn)通用數(shù)據(jù)庫(kù)清理
項(xiàng)目如果需要存儲(chǔ)很多日志記錄比如運(yùn)行日志,時(shí)間長(zhǎng)了記錄數(shù)量非常多,數(shù)據(jù)庫(kù)體積不斷增大,對(duì)應(yīng)數(shù)據(jù)庫(kù)表的增刪改查的效率不斷降低,因此需要將早期的數(shù)據(jù)清理。本文將詳細(xì)介紹一下通用數(shù)據(jù)庫(kù)清理的實(shí)現(xiàn),需要的可以參考一下2022-02-02C++中priority_queue的使用與模擬實(shí)現(xiàn)
本文主要介紹了C++中priority_queue的使用與模擬實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02Matlab計(jì)算變異函數(shù)并繪制經(jīng)驗(yàn)半方差圖詳解
這篇文章主要為大家詳細(xì)介紹了基于MATLAB求取空間數(shù)據(jù)的變異函數(shù),并繪制經(jīng)驗(yàn)半方差圖的方法。文中的示例代碼講解詳細(xì),感興趣的可以了解一下2023-04-04C語(yǔ)言中結(jié)構(gòu)體struct編寫(xiě)的一些要點(diǎn)解析
這篇文章主要介紹了C語(yǔ)言中結(jié)構(gòu)體struct編寫(xiě)的一些要點(diǎn)解析,談到了結(jié)構(gòu)體的聲明和指針指向等重要知識(shí)點(diǎn),需要的朋友可以參考下2016-04-04C++實(shí)現(xiàn)打印兩個(gè)有序鏈表公共部分的方法
這篇文章主要介紹了C++實(shí)現(xiàn)打印兩個(gè)有序鏈表公共部分的方法,涉及C++針對(duì)有序鏈表的簡(jiǎn)單遍歷、比較相關(guān)操作技巧,需要的朋友可以參考下2017-05-05C語(yǔ)言實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)迷宮實(shí)驗(yàn)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)迷宮實(shí)驗(yàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03