淺析C++模板類型中的原樣轉(zhuǎn)發(fā)和可變參數(shù)的實(shí)現(xiàn)
原樣轉(zhuǎn)發(fā)的意義
前文我們實(shí)現(xiàn)了一個my_move函數(shù),用來模擬stl的move操作,實(shí)現(xiàn)去引用的功能。其內(nèi)部的原理就是通過remove_reference實(shí)現(xiàn)去引用操作。
有時我們也需要保留原類型的左值或者右值屬性,進(jìn)行原樣轉(zhuǎn)發(fā),此時就要用forward實(shí)現(xiàn)轉(zhuǎn)發(fā)功能。
我們先定義一個模板函數(shù)
template <typename F, typename T1, typename T2> void flip1(F f, T1 t1, T2 t2) { f(t2, t1); }
flip1內(nèi)部調(diào)用了函數(shù)f
我們寫一個函數(shù)測試
void ftemp(int v1, int &v2) { cout << v1 << " " << ++v2 << endl; } void use_ftemp(){ int j = 100; int i = 99; flip1(ftemp, j, 42); cout << "i is " << i << " j is " << j << endl; }
通過打印發(fā)現(xiàn)i和j的值沒有變化,因?yàn)閒temp的v2參數(shù)雖然是引用,但是是flip1的形參t1的引用
t1只是形參,修改t1并不能影響外邊的實(shí)參j。
想要達(dá)到修改實(shí)參的目的,需要將flip1的參數(shù)修改為引用,我們先實(shí)現(xiàn)修改后的版本flip2
template <typename F, typename T1, typename T2> void flip2(F f, T1 &&t1, T2 &&t2) { f(t2, t1); }
我們定義了一個flip2函數(shù),t1和t2分別是右值引用類型。接下來用一個測試函數(shù)進(jìn)行測試
int j = 100; int i = 99; flip2(ftemp, j, 42); cout << "i is " << i << " j is " << j << endl;
這次我們發(fā)現(xiàn)j被修改了,因?yàn)閒lip2的t1參數(shù)類型為T1的右值引用,當(dāng)把實(shí)參j賦值給flip2時,T1變?yōu)閕nt&,
t1的類型就是int& &&,通過折疊t1變?yōu)閕nt&類型。這樣t1就和實(shí)參j綁定了,在flip2內(nèi)部修改t1,就達(dá)到了修改j的目的。
但是flip2同樣存在一個問題,如果flip2的第一個參數(shù)f,如果f是一個接受右值引用參數(shù)的函數(shù),會出現(xiàn)編譯錯誤。
為說明這一點(diǎn),我們實(shí)現(xiàn)一個接納模板參數(shù)右值引用類型的函數(shù)
void gtemp(int &&i, int &j) { cout << "i is " << i << " j is " << j << endl; }
此時如果我們將gtemp作為參數(shù)傳遞給flip2會報錯
int j = 100; int i = 99; // flip2(gtemp, j, 42) 會報錯 // 因?yàn)?2作為右值純遞給flip2,t2會被折疊為int&類型 // t2傳遞給gtemp第一個參數(shù)時,int&&無法綁定int&類型 //flip2(gtemp, i, 42); cout << "i is " << i << " j is " << j << endl;
當(dāng)我們將42傳遞給flip2第二個參數(shù)時,T2被實(shí)例化為int類型,t2就變?yōu)閕nt && 類型,通過折疊t2變?yōu)閕nt&類型。
t2作為參數(shù)傳遞給gtemp的第一個參數(shù)時會報錯,
cannot bind rvalue reference of type ‘int&&’ to lvalue of type ‘int’
因?yàn)閠2是一個左值,右值無法綁定該左值。
解決的辦法就是實(shí)現(xiàn)一個flip函數(shù),內(nèi)部實(shí)現(xiàn)對T2,T1類型的原樣轉(zhuǎn)發(fā)。
template <typename F, typename T1, typename T2> void flip(F f, T1 &&t1, T2 &&t2) { f(std::forward<T2>(t2), std::forward<T1>(t1)); }
通過forward將t2類型轉(zhuǎn)化為和T2類型一樣的類型,也就是int的右值類型,接下來的調(diào)用就不會出問題了
void use_ftemp() { int j = 100; int i = 99; flip(gtemp, i, 42); cout << "i is " << i << " j is " << j << endl; }
模板的可變參數(shù)
模板同樣支持可變參數(shù)
//可變參數(shù)的函數(shù)模板 template <typename T> ostream &print(ostream &os, const T &t) { return os << t; //輸出最后一個元素 } template <typename T, typename... Args> ostream &print(ostream &os, const T &t, const Args &...rest) { os << t << ", "; return print(os, rest...); }
Args是可變的模板參數(shù)包, 然后再用Args定義rest變量,這是一個可變參數(shù)列表。
我們的模板函數(shù)print內(nèi)部調(diào)用stl的print函數(shù),通過對rest…實(shí)現(xiàn)展開操作。
調(diào)用過程可按如下的方式
void use_printtemp() { int i = 100; string s = "hello zack!!!"; print(cout, i, s, 42); }
第一次調(diào)用print實(shí)際是調(diào)用的可變參數(shù)的print,之后才調(diào)用沒有可變參數(shù)的print函數(shù)。
總結(jié)
本文介紹了模板類型的原樣轉(zhuǎn)發(fā),以及多模板參數(shù)列表的使用。
到此這篇關(guān)于淺析C++模板類型中的原樣轉(zhuǎn)發(fā)和可變參數(shù)有什么意義的文章就介紹到這了,更多相關(guān)C++原樣轉(zhuǎn)發(fā)和可變參數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Qt與Web混合開發(fā)實(shí)現(xiàn)雙向通信的示例
本文主要介紹了Qt與Web混合開發(fā)實(shí)現(xiàn)雙向通信的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07c++實(shí)現(xiàn)加載so動態(tài)庫中的資源
下面小編就為大家?guī)硪黄猚++實(shí)現(xiàn)加載so動態(tài)庫中的資源。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-12-12