日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

item 24: 区分右值引用和universal引用

發(fā)布時(shí)間:2023/12/13 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 item 24: 区分右值引用和universal引用 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文翻譯自《effective modern C++》,由于水平有限,故無(wú)法保證翻譯完全正確,歡迎指出錯(cuò)誤。謝謝!

博客已經(jīng)遷移到這里啦

古人曾說(shuō)事情的真相會(huì)讓你覺得很自在,但是在適當(dāng)?shù)那闆r下,一個(gè)良好的謊言同樣能解放你。這個(gè)Item就是這樣一個(gè)謊言。但是,因?yàn)槲覀冊(cè)诤蛙浖蚪坏?#xff0c;所以讓我們避開“謊言”這個(gè)詞,換句話來(lái)說(shuō):本Item是由“抽象”組成的。

為了聲明一個(gè)指向T類型的右值引用,你會(huì)寫T&&。因此我們可以“合理”地假設(shè):如果你在源代碼中看到“T&&”,你就看到了一個(gè)右值引用。可惜地是,它沒有這么簡(jiǎn)單:

void f(Widget&& param); // 右值引用Widget&& var1 = Widget(); // 右值引用auto&& var2 = var1; // 不是右值引用template<typename T> void f(std::vector<T>&& param); // 右值引用template<typename T> void f(T&& param); // 不是右值引用

事實(shí)上,“T&&”有兩個(gè)不同的意思。當(dāng)然,其中一個(gè)是右值引用。這樣引用行為就是你所期望的:它們只綁定到右值上去,并且它們的主要職責(zé)就是去明確一個(gè)對(duì)象是可以被move的。

“T&&”的另外一個(gè)意思不是左值引用也不是右值引用。這樣的引用看起來(lái)像是在源文件中的右值引用(也就是,“T&&”),但是它能表現(xiàn)得像是一個(gè)左值引用(也就是“T&”)一樣。它這樣的兩重意義讓它能綁定到左值(就像左值引用)上去,也能綁定到右值(就像右值引用)上去。另外,它能綁定到const或非const對(duì)象上去,也能綁定到volatile或非volatile對(duì)象上去,甚至能綁定到const加volatile的對(duì)象上去。它能綁定到幾乎任何東西上去。這樣空前靈活的引用理應(yīng)擁有它們自己的名字,我叫它們universal引用(萬(wàn)能引用)。

universal引用出現(xiàn)在兩種上下文中。最通用的情況是在函數(shù)模板參數(shù)中,就像來(lái)自于上面示例代碼的這個(gè)例子一樣:

template<typename T> void f(T&& param); // param是一個(gè)universal引用

第二個(gè)情況是auto聲明,包括上面示例代碼中的這一行代碼:

auto&& var2 = var1; // var2是一個(gè)universal引用

這兩個(gè)情況的共同點(diǎn)就是它們都存在類型推導(dǎo)。在模板f中,param的類型正在被推導(dǎo),并且在var2的聲明式中,var2的類型正在被推導(dǎo)。把它們和下面的例子(它們不存在類型推導(dǎo),同樣來(lái)自上面的示例代碼)比較一下,可以發(fā)現(xiàn),如果你看到不存在類型推導(dǎo)的“T&&”時(shí),你能把它視為右值引用:

void f(Widget&& param); // 沒有類型推導(dǎo)// param是右值引用Widget&& var1 = Widget(); // 沒有類型推導(dǎo)// param是右值引用

因?yàn)閡niversal引用是引用,它們必須被初始化。universal引用的初始化決定了它代表一個(gè)右值還是一個(gè)左值。如果初始化為一個(gè)右值,universal引用對(duì)應(yīng)右值引用。如果初始化為一個(gè)左值,universal引用對(duì)應(yīng)一個(gè)左值引用。對(duì)于那些屬于函數(shù)參數(shù)的universal引用,它在調(diào)用的地方被初始化:

template<typename T> void f(T&& param); // param是一個(gè)universal引用Widget w; f(w); // 左值被傳給f,param的類型是// Widget&(也就是一個(gè)左值引用)f(std::move(w)); // 右值被傳給f,param的類型是// Widget&&(也就是一個(gè)右值引用)

要讓一個(gè)引用成為universal引用,類型推導(dǎo)是其必要不補(bǔ)充條件。引用聲明的格式必須同時(shí)正確才行,而且格式很嚴(yán)格。它必須正好是“T&&”。再看一次這個(gè)我們之前在示例代碼中看過(guò)的例子:

template<typename T> void f(std::vector<T>&& param); // param是一個(gè)右值引用

當(dāng)f被調(diào)用時(shí),類型T將被推導(dǎo)(除非調(diào)用者顯式地指定它,這種邊緣情況我們不關(guān)心)。但是param類型推導(dǎo)的格式不是“T&&”,而是“std::vector&&”。按照上面的規(guī)則,排除了param成為一個(gè)universal引用的可能性。因此param是一個(gè)右值引用,有時(shí)候你的編譯器會(huì)很高興地為你確認(rèn)你是否傳入了一個(gè)左值給f:

std::vector<int> v; f(v); // 錯(cuò)誤!不能綁定一個(gè)左值到右值// 引用上去

甚至一個(gè)簡(jiǎn)單的const屬性的出場(chǎng)就足以取消引用成為universal的資格:

template<typename T> void f(const T&& param); // param是一個(gè)右值引用

如果你在一個(gè)模板中,并且你看到一個(gè)“T&&”類型的函數(shù)參數(shù),你可能覺得你能假設(shè)它是一個(gè)universal引用。但是你不能,因?yàn)樵谀0逯胁荒鼙WC類型推導(dǎo)的存在。考慮一下std::vector中的這個(gè)push_back成員函數(shù):

template<class T, class Allocator = allocator<T>> //來(lái)自c++標(biāo)準(zhǔn)庫(kù) class vector { public:void push_back(T&& x);... };

push_back的參數(shù)完全符合universal引用的格式,但是在這個(gè)情況中沒有類型推導(dǎo)發(fā)生。因?yàn)閜ush_back不能存在于vector的特定實(shí)例之外,并且實(shí)例的類型就完全能決定push_back的聲明類型了。也就是說(shuō)

std::vector<Widget> v;

使得std::vector模板被實(shí)例化為下面這樣:

class vector<Widget, allocator<Widget>> { public:void push_back(Widget&& x); //右值引用... };

現(xiàn)在你能清楚地發(fā)現(xiàn)push_back沒有用到類型推導(dǎo)。vector的這個(gè)push_back(vector中有兩個(gè)push_back函數(shù))總是聲明一個(gè)類型是rvalue-reference-to-T(指向T的右值引用)的參數(shù)。

不同的是,std::vector中和push_back概念上相似的emplace_back成員函數(shù)用到了類型推導(dǎo):

template<class T, class Allocator = allocator<T>> class vector { public:template <class... Args>void emplace_back(Args&&... args);... };

在這里,類型參數(shù)Args獨(dú)立于vector的類型參數(shù)T,所以每次emplace_back被調(diào)用的時(shí)候,Args必須被推導(dǎo)。(好吧,Args事實(shí)上是一個(gè)參數(shù)包,不是一個(gè)類型參數(shù),但是為了討論的目的,我們能把它視為一個(gè)類型參數(shù)。)

事實(shí)上emplace_back的類型參數(shù)被命名為Args(不是T),但是它仍然是一個(gè)universal引用,之前我說(shuō)universal引用的格式必須是“T&&”。在這里重申一下,我沒要求你必須使用名字T。舉個(gè)例子。下面的模板使用一個(gè)universal引用,因?yàn)楦袷?#xff08;“type&&”)是正確的,并且param的類型將被推導(dǎo)(再說(shuō)一次,除了調(diào)用者顯式指定類型的邊緣情況):

template<typename MyTemplateType> // param是一個(gè)void someFunc(MyTemplateType&& param); // universal引用

我之前說(shuō)過(guò)auto變量也能是universal引用。更加精確一些,用auto&&的格式被推導(dǎo)的變量是universal引用,因?yàn)轭愋屯茖?dǎo)有發(fā)生,并且它有正確的格式(“T&&”)。auto universal引用不像用于函數(shù)模板參數(shù)的universal引用那么常見,但是他們有時(shí)候會(huì)在C++11中突然出現(xiàn)。他們?cè)贑++14中出現(xiàn)的頻率更高,因?yàn)镃++14的lambda表達(dá)式可以聲明auto&&參數(shù)。舉個(gè)例子,如果你想要寫一個(gè)C++14的lambda來(lái)記錄任意函數(shù)調(diào)用花費(fèi)的時(shí)間,你能這么做:

auto timeFuncInvocation =[](auto&& func, auto&&... param){start timer;std::forward<decltype(func)>(func){ // 用paramsstd::forward<decltype(params)>(params)... // 調(diào)用func};停止timer并記錄逝去的時(shí)間。};

如果你對(duì)lambda中“std::forward<decltype(blah blah blah)>”(譯注:blah blah blah發(fā)音為:布拉布拉布拉)的代碼感到困惑,這可能只是意味著你還沒讀過(guò)Item 33.不要擔(dān)心這件事。在本Item中,重要的事情是lambda表達(dá)式中聲明的auto&&參數(shù)。func是一個(gè)universal引用,它能被綁定到任何調(diào)用的對(duì)象上去,不管是左值還是右值。params(譯注:原文為args,應(yīng)該是筆誤)是0個(gè)或多個(gè)universal引用(也就是一個(gè)universal引用包),它能被綁定到任何數(shù)量的任意類型的對(duì)象上去。結(jié)果就是,由于auto universal引用的存在,timeFuncInvocation能給絕大多數(shù)函數(shù)的執(zhí)行進(jìn)行計(jì)時(shí)。(對(duì)于為什么是絕大多數(shù)而不是任意,請(qǐng)看Item 30。)

把這件事記在心里:我們這整個(gè)Item(universal引用的基礎(chǔ))都是一個(gè)謊言...額,一個(gè)“抽象”!潛在的事實(shí)被稱為引用折疊,這個(gè)話題會(huì)在Item 28中專門討論。但是事實(shí)并不會(huì)讓抽象失效。區(qū)分右值引用和universal引用將幫助你更精確地閱讀源代碼(“我看到的T&&只能綁定到右值上,還是能綁定到所有東西上呢?”),并且在你和同事討論的時(shí)候,它能讓你避免歧義。(“我在這里使用一個(gè)universal引用,不是一個(gè)右值引用...”)。它也能讓你搞懂Item 25和Item 26的意思,這兩個(gè)Item都依賴于這兩個(gè)引用的區(qū)別。所以,擁抱抽象并陶醉于此吧。就像牛頓的運(yùn)動(dòng)定律(學(xué)術(shù)上來(lái)說(shuō)是錯(cuò)誤的)一樣,比起愛因斯坦的相對(duì)論(“事實(shí)”)來(lái)說(shuō)它通常一樣好用并且更簡(jiǎn)單,universal引用的概念也是這樣,比起工作在引用折疊的細(xì)節(jié)來(lái)說(shuō),它是更好的選擇。

            你要記住的事
  • 如果一個(gè)函數(shù)模板參數(shù)有T&&的格式,并且會(huì)被推導(dǎo),或者一個(gè)對(duì)象使用auto&&來(lái)聲明,那么參數(shù)或?qū)ο缶褪且粋€(gè)universal引用。
  • 如果類型推導(dǎo)的格式不是準(zhǔn)確的type&&,或者如果類型推導(dǎo)沒有發(fā)生,type&&就是一個(gè)右值引用。
  • 如果用右值來(lái)初始化,universal引用相當(dāng)于右值引用。如果用左值來(lái)初始化,則相當(dāng)于左值引用。

轉(zhuǎn)載于:https://www.cnblogs.com/boydfd/p/5251797.html

總結(jié)

以上是生活随笔為你收集整理的item 24: 区分右值引用和universal引用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日韩一区二区三区在线观看视频 | 欧美福利小视频 | 三级黄色片免费 | 鲁丝片一区二区三区 | 国产精品无码久久久久久电影 | 亚洲黄色小说图片 | 国产中文字幕91 | 天天爽夜夜 | 韩国美女视频在线观看18 | 久久婷婷久久 | 一区精品二区国产 | 久久精品国产大片免费观看 | 久久久激情网 | 亚洲精品www. | 加勒比一区二区 | 九九热视频精品在线观看 | 国产在线观看黄 | 国产乱国产 | 国产真人做爰视频免费 | 久久1024 | 伊人久久大香线蕉av色婷婷色 | 性久久久久久久 | 日韩精品网站 | 第一区免费在线观看 | 97超碰97| 假日游船 | 91视频免费网站 | 天堂av成人| 精品一区二区三区免费看 | 视频一区三区 | 国产精品视频久久久久久 | 一区二区三区黄色录像 | 国产片久久 | 男人桶进美女尿囗 | www.youjizz.com中国| jizz成熟丰满老女人 | 色久综合| 国内偷拍久久 | 影音先锋婷婷 | 日韩一级色 | 欧美视频在线不卡 | 黄色日比视频 | 欧美综合日韩 | 亚洲国产精品国自产拍久久 | 亚洲午夜久久久久久久久久久 | 国产区高清 | 午夜男人的天堂 | 日本在线观看www | 污视频在线网站 | 日本中文在线播放 | 亚洲国产精品99 | 成av人片在线观看www | 美女啪啪免费视频 | 日本一区二区高清不卡 | 亚洲天堂手机在线观看 | 中文在线字幕观看 | 91麻豆蜜桃一区二区三区 | 精品在线你懂的 | 欧美成人精品二区三区99精品 | 青春草国产视频 | 大地资源二中文在线影视观看 | 91中文字幕网 | 午夜久久电影 | 男男h黄动漫啪啪无遮挡软件 | 农村妇女毛片 | 日本精品一区二区 | av在线视屏 | 国产a视频 | 欧美成年人在线观看 | 国产一级片视频 | 国产黄色大片在线观看 | 国产美女无遮挡免费 | 男女激情视频网站 | 欧美乱大交xxxxx潮喷 | 美女免费黄视频 | 国产成人精品一区二区 | 成人免费毛片片v | 国产国拍精品亚洲 | 九一亚洲精品 | 日本视频免费 | 波多野结衣av在线免费观看 | 欧美,日韩,国产精品免费观看 | 三级性生活视频 | 少妇一级淫片免费 | 奇米影视大全 | 爱爱免费视频网站 | 国产免费a视频 | 九九热精品免费视频 | 欧美日韩电影一区二区三区 | 中文字幕在线视频一区二区 | 黑人乱码一区二区三区av | 韩国三级中文字幕hd久久精品 | 超碰av男人的天堂 | 免费看av的网址 | 少妇久久久久久久 | 久久久久久久久久国产 | 精品中文字幕视频 | 久久精品一区二区 | 中国极品少妇xxxx做受 |