C++?折疊參數(shù)包詳解(悄然增強(qiáng)編程效率)
前言
本節(jié)將為大家?guī)?lái)折疊參數(shù)包的詳細(xì)講解,折疊參數(shù)包為C++模板編程提供了更加靈活和強(qiáng)大的工具,可以提高代碼的簡(jiǎn)潔性和可讀性,看完后希望對(duì)你有收獲
一、介紹
折疊參數(shù)就是一個(gè)參數(shù)包, 代表是多個(gè)未知,tuple元組就是一個(gè)折疊參數(shù)的使用
折疊參數(shù)類(lèi)型:
typename ...Args:
Args參數(shù)包的包名 ,本質(zhì)是聲明一個(gè)Args折疊參數(shù)類(lèi)型Args ...arg:
折疊參數(shù)包類(lèi)型的變量...:
理解為多個(gè)意思
二、函數(shù)模板中使用折疊參數(shù)
1、遞歸方式展開(kāi)
遞歸方式的展開(kāi)是比較好理解的,每一次調(diào)用第二個(gè)print函數(shù)就打印一次data,然后又調(diào)用自己,這時(shí)候參數(shù)包也剝離了一個(gè)參數(shù),也就是調(diào)用自己會(huì)打印下一個(gè)data
有的同學(xué)看了下面的代碼可能會(huì)疑惑,為什么會(huì)有兩個(gè)函數(shù),這是因?yàn)樯厦娴暮瘮?shù)為終止函數(shù),也就是當(dāng)?shù)诙€(gè)函數(shù)參數(shù)包中只有一個(gè)參數(shù)時(shí)調(diào)用第一個(gè)函數(shù)
template <typename _Ty> void print(_Ty data) { cout << data << endl; } template <typename _Ty,typename ...Args> void print(_Ty data, Args ...args) { cout << data << "\t"; print(args...); }
2、列表數(shù)據(jù)展開(kāi)
這個(gè)的難點(diǎn)和重點(diǎn)在于initializer_list<int>{(printData(args), 0)...};
,這一行代碼用到了列表和逗號(hào)表達(dá)式的特性,不用說(shuō)列表的每個(gè)值最后都被初始化為0,但是列表的每個(gè)值被初始化為0的時(shí)候,他們會(huì)先執(zhí)行printData(args(n))
,也就是會(huì)不斷打印,參數(shù)包不斷展開(kāi)
template <typename _Ty> void printData(_Ty data) { cout << data << "\t"; } template <typename ...Args> void printArgs(Args ...args) { initializer_list<int>{(printData(args), 0)...}; cout << endl; }
3、完美轉(zhuǎn)發(fā)的方式展開(kāi)
完美轉(zhuǎn)發(fā)一般是用來(lái)統(tǒng)一接口,也就是有許多函數(shù),他們的參數(shù)數(shù)量、類(lèi)型不同,我們把他們統(tǒng)一為只用函數(shù)名就可以調(diào)用該函數(shù),且不減少其原功能
這里我們用仿函數(shù)接收一下用bind綁定的函數(shù)以及參數(shù)包,注意這里函數(shù)和參數(shù)包綁定的時(shí)候都用了完美轉(zhuǎn)發(fā)
什么是完美轉(zhuǎn)發(fā)吶?forword是為了解決在函數(shù)模板中,使用右值引用參數(shù)(T&&),傳遞右值進(jìn)去以后,類(lèi)型會(huì)變?yōu)樽笾档膯?wèn)題。當(dāng)傳入的參數(shù)是一個(gè)對(duì)象時(shí),右值變左值就會(huì)出問(wèn)題,因?yàn)樽笾嫡{(diào)用拷貝構(gòu)造,右值調(diào)用移動(dòng)構(gòu)造。本來(lái)可以用移動(dòng)構(gòu)造提高效率,卻因?yàn)橛抑底兂勺笾?,調(diào)用了拷貝構(gòu)造。所以我們要把它變回去!實(shí)參傳的是右值,進(jìn)入函數(shù)體還是右值,這就是完美轉(zhuǎn)發(fā)
class Test { public: void printk() { if (func) func(); } template <typename Func,typename ...Args> void connect(Func&& f, Args&& ...args) //右值引用 { func = bind(forward<Func>(f), forward<Args>(args)...); } protected: function<void()> func; }; void sum(int a, int b) { cout<< a + b; } int main() { Test test; test.connect(sum, 1, 2); test.printk(); test.connect([](int a, int b) {cout << endl << a + b; }, 3, 8); test.printk(); return 0; }
上面的例子中通過(guò)connect
綁定函數(shù)和參數(shù)包,實(shí)現(xiàn)統(tǒng)一接口的功能,通過(guò)printK
函數(shù)調(diào)用
三、類(lèi)模板中使用折疊參數(shù)
1、繼承+模板特化的方式展開(kāi)
類(lèi)中實(shí)現(xiàn)折疊參數(shù),前兩個(gè)類(lèi)是必須,對(duì)應(yīng)上面的終止函數(shù),繼承的時(shí)候要寫(xiě)清楚public Test<Args...>
,還有就是第三個(gè)類(lèi)必須要一個(gè)無(wú)參構(gòu)造函數(shù),且?guī)?shù)包的的構(gòu)造函數(shù)初始化時(shí)要調(diào)用子類(lèi)的構(gòu)造函數(shù),還有就是打印的時(shí)候要一層一層的,采用繼承+模板特化就是一代一代的
template <typename ...Args> class Test; template<> class Test<> {}; template <typename _Ty, typename ...Args> class Test<_Ty, Args...> :public Test<Args...> { public: Test() {} Test(_Ty data, Args ...args) :data(data), Test<Args...>(args...) {} Test<Args...>& getObject() { return *this; } _Ty& getData() { return data; } protected: _Ty data; }; void testOne() { Test<string, int, double> test("fsdjf", 32, 3.23); cout << test.getData() << "\t" << test.getObject().getData() << "\t" << test.getObject().getObject().getData() << endl; }
2、遞歸的方式展開(kāi)
遞歸這一種就是把自己當(dāng)對(duì)象調(diào)用,其它的和上面相同
template <typename ...Args> class my_tuple; template<> class my_tuple<> {}; template <typename _Ty, typename ...Args> class my_tuple<_Ty, Args...> { public: my_tuple() {} my_tuple(_Ty data, Args ...args) :data(data),args(args...) {} _Ty& getData() { return data; } my_tuple<Args...>& getObject() { return *this; } protected: _Ty data; my_tuple<Args...> args; }; void testTwo() { Test<string, int, double> test("fsdjf", 32, 3.23); cout << test.getData() << "\t" << test.getObject().getData() << "\t" << test.getObject().getObject().getData() << endl; }
到此這篇關(guān)于C++ 折疊參數(shù)包悄然增強(qiáng)編程效率的文章就介紹到這了,更多相關(guān)C++ 折疊參數(shù)包內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)宿舍管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)宿舍管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06OpenSSL動(dòng)態(tài)鏈接庫(kù)源碼安裝教程
Openssl 是一個(gè)開(kāi)放源代碼的SSL協(xié)議的產(chǎn)品實(shí)現(xiàn),它采用C語(yǔ)言作為開(kāi)發(fā)語(yǔ)言,具備了跨系統(tǒng)的性能。這篇文章主要介紹了OpenSSL動(dòng)態(tài)鏈接庫(kù)源碼安裝,需要的朋友可以參考下2021-11-11C語(yǔ)言實(shí)現(xiàn)折半查找法(二分法)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)折半查找法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11C語(yǔ)言 鏈?zhǔn)蕉鏄?shù)結(jié)構(gòu)詳解原理
二叉樹(shù)的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)是指,用鏈表來(lái)表示一棵二叉樹(shù),即用鏈來(lái)指示元素的邏輯關(guān)系。通常的方法是鏈表中每個(gè)結(jié)點(diǎn)由三個(gè)域組成,數(shù)據(jù)域和左右指針域,左右指針?lè)謩e用來(lái)給出該結(jié)點(diǎn)左孩子和右孩子所在的鏈結(jié)點(diǎn)的存儲(chǔ)地址2021-11-11C++中的函數(shù)指針與函數(shù)對(duì)象的總結(jié)
以下是對(duì)C++中的函數(shù)指針與函數(shù)對(duì)象的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以參考下2013-07-07C語(yǔ)言分別實(shí)現(xiàn)棧和隊(duì)列詳解流程
棧和隊(duì)列,嚴(yán)格意義上來(lái)說(shuō),也屬于線性表,因?yàn)樗鼈円捕加糜诖鎯?chǔ)邏輯關(guān)系為 "一對(duì)一" 的數(shù)據(jù),但由于它們比較特殊,因此將其單獨(dú)作為一章,做重點(diǎn)講解2022-04-04