一文搞懂C++11萬(wàn)能引用和右值引用
前言
我們通過(guò)一個(gè)問(wèn)題來(lái)進(jìn)入今天的話題:
1.形如 “type&&” 的結(jié)構(gòu),就是右值引用嗎?
2.以下哪些屬于右值引用?
① void fun(Widget && param);
② Widget && var1= Widget();
③ auto && var2 = var1;
④ template<typename T> void f(std::vector<T>&& param);
⑤ template<typename T> void f(T&& param);
帶著以上的問(wèn)題,我們來(lái)看一下到底type&&的結(jié)構(gòu)包含了哪些含義。
正文
實(shí)際上,type&& 有兩種不同的含義。
其中一種就是 右值引用。它僅僅會(huì)綁定右值,用于識(shí)別出可移對(duì)象。
另外一種含義,則表示既可以是右值引用,也可以是左值引用。這種雙重特性使其可以綁定到右值,也可以綁定到左值。還可以綁定到const對(duì)象或非const對(duì)象,以及volatile對(duì)象,甚至可以綁定那些既帶有const又帶有volatile的對(duì)象,擁有很強(qiáng)的靈活性,這就是萬(wàn)能引用。
那么,既然以上兩種含義都是 type&& 結(jié)構(gòu),那么如何來(lái)區(qū)分二者呢?
萬(wàn)能引用
萬(wàn)能引用通常會(huì)在兩種場(chǎng)景現(xiàn)身:函數(shù)模板的形參 和 auto聲明。
示例如下:
template<typename T> void f(T&& param); //param是個(gè)萬(wàn)能引用
auto && var2 = var1;
以上兩種場(chǎng)景的共同之處,在于它們都涉及型別推導(dǎo)。
在模板f中,param的類(lèi)型是推導(dǎo)得到的,而在var2的聲明語(yǔ)句中,var2的類(lèi)型也是推導(dǎo)得到的。
因?yàn)槿f(wàn)能引用首先是個(gè)引用,所以初始化是必須的。萬(wàn)能引用的初始化物會(huì)決定它代表的是個(gè)左值還是右值引用,如果初始化物是左值,萬(wàn)能引用就會(huì)對(duì)應(yīng)得到一個(gè)左值引用,同理,如果初始化物是右值,萬(wàn)能引用就會(huì)對(duì)應(yīng)得到一個(gè)右值引用。
對(duì)于作為函數(shù)形參的萬(wàn)能引用而言,初始化物在調(diào)用處提供:
template<typename T>? void f(T&& param); Widget w; f(w); ? ?? ??? ? ?//左值被傳遞給f,param的類(lèi)型是Widget&,即左值引用 f(std::move(w)); ?//右值被傳遞給f,param的類(lèi)型是Widget&&,即右值引用
有一個(gè)需要注意的問(wèn)題是,萬(wàn)能引用除了要涉及型別推導(dǎo),還有一個(gè)條件必須限定,就是必須要是“T&&”結(jié)構(gòu)才行。
而類(lèi)似
template<typename T> void f(std::vector<T>&& param); //param是右值引用
這樣的類(lèi)型并不是萬(wàn)能引用,僅僅只是一個(gè)右值引用。
而且,如果有const修飾也不可能成為萬(wàn)能引用,比如:
template<typename T> void f(const T&& param); //param是右值引用
那么,位于模板內(nèi)是不是就一定就會(huì)涉及到型別推導(dǎo)呢? 還真不能保證??匆韵率纠?/p>
template <class T,class Allocator = allocator<T>> class vector{ public: void push_back(T&& x); ... };
以上是來(lái)自C++標(biāo)準(zhǔn)中vector類(lèi)
這里的push_back的形參具備萬(wàn)能引用的正確形式,但是在本示例中,并不涉及到類(lèi)型推導(dǎo)。因?yàn)閜ush_back作為vector本身的一部分,如果不存在特定的vector實(shí)例,則它也無(wú)從存在。該實(shí)例的具體類(lèi)型完全決定了push_back的聲明類(lèi)型。
如:
std::vector<Widget> v;
會(huì)導(dǎo)致std::vector模板具現(xiàn)化為如下實(shí)例:
template <class Widget,class Allocator = allocator<Widget>> class vector{ public: void push_back(Widget&& x); //右值引用 ... };
現(xiàn)在就能看清楚push_back并未涉及到類(lèi)型推導(dǎo)。
而vector中的另外一個(gè)函數(shù)卻涉及到了類(lèi)型推導(dǎo),如下:
template <class T,class Allocator = allocator<T>> class vector{ public: template<class... Args> void emplace_back(Args&&... args); ... };
以上emplace_back函數(shù)的形參 Args獨(dú)立于vector的型別形參T,所以Args必須在每次emplace_back被調(diào)用時(shí)進(jìn)行推導(dǎo)。所以這里的args是個(gè)萬(wàn)能引用。
最后,我們前面也提到過(guò),auto變量也可以作為萬(wàn)能引用。確切的說(shuō),聲明為auto&&的變量都是萬(wàn)能引用,因?yàn)榭隙ㄉ婕暗叫蛣e推導(dǎo)并且肯定有正確的形式(“T&&”)
比如在C++14中 lambda表達(dá)式可以聲明auto&&形參。
結(jié)語(yǔ)
通過(guò)以上描述,終于搞清楚了萬(wàn)能引用和右值引用的區(qū)別,那么回到文中最前面的問(wèn)題,③⑤都是萬(wàn)能引用,其他三個(gè)為右值引用,這下不會(huì)搞錯(cuò)了。
總結(jié)如下:
- 如果函數(shù)模板形參具備T&&型別,并且T的型別是推導(dǎo)而來(lái),或如果對(duì)象使用auto&&聲明其類(lèi)型,則該形參或?qū)ο缶褪侨f(wàn)能引用
- 如果型別聲明不精確地具備type&&的形式,或者型別推導(dǎo)并未發(fā)生,則type&&就代表右值引用
- 若采用右值來(lái)初始化萬(wàn)能引用,就會(huì)得到一個(gè)右值引用,如果采用左值來(lái)初始化,則會(huì)得到一個(gè)左值引用。
參考:
到此這篇關(guān)于一文搞懂C++11萬(wàn)能引用和右值引用的文章就介紹到這了,更多相關(guān)C++11萬(wàn)能引用和右值引用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言中操作utmp文件的相關(guān)函數(shù)用法
這篇文章主要介紹了C語(yǔ)言中操作utmp文件的相關(guān)函數(shù)用法,包括getutent()函數(shù)和setutent()函數(shù)以及endutent()函數(shù),需要的朋友可以參考下2015-08-08C語(yǔ)言詳解無(wú)頭單向非循環(huán)鏈表各種操作方法
無(wú)頭單向非循環(huán)鏈表:結(jié)構(gòu)簡(jiǎn)單,一般不會(huì)單獨(dú)用來(lái)存數(shù)據(jù)。實(shí)際中更多是作為其他數(shù)據(jù)結(jié)構(gòu)的子結(jié)構(gòu),如哈希桶、圖的鄰接表等等。另外這種結(jié)構(gòu)在筆試面試中出現(xiàn)很多2022-04-04內(nèi)聯(lián)函數(shù)inline與宏定義深入解析
類(lèi)的內(nèi)斂函數(shù)是一個(gè)真正的函數(shù)。使用內(nèi)聯(lián)函數(shù)inline可以完全取代表達(dá)式形式的宏定義2013-09-09C語(yǔ)言計(jì)算代碼執(zhí)行所耗CPU時(shí)鐘周期
本文給大家介紹的是使用C語(yǔ)言來(lái)計(jì)算代碼執(zhí)行所耗CPU時(shí)鐘周期的代碼,非常的簡(jiǎn)單實(shí)用,不過(guò)要依托于sync,有需要的小伙伴自己參考下吧。2015-03-03