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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++11:搞清楚万能引用和右值引用

發布時間:2024/1/1 c/c++ 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++11:搞清楚万能引用和右值引用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

我們通過一個問題來進入今天的話題:
1.形如 “type&&” 的結構,就是右值引用嗎?
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);

帶著以上的問題,我們來看一下到底type&&的結構包含了哪些含義。

正文

實際上,type&& 有兩種不同的含義。
其中一種就是 右值引用。它僅僅會綁定右值,用于識別出可移對象。
另外一種含義,則表示既可以是右值引用,也可以是左值引用。這種雙重特性使其可以綁定到右值,也可以綁定到左值。還可以綁定到const對象或非const對象,以及volatile對象,甚至可以綁定那些既帶有const又帶有volatile的對象,擁有很強的靈活性,這就是萬能引用

那么,既然以上兩種含義都是 type&& 結構,那么如何來區分二者呢?

萬能引用

萬能引用通常會在兩種場景現身:函數模板的形參 和 auto聲明。
示例如下:

template<typename T> void f(T&& param); //param是個萬能引用 auto && var2 = var1;

以上兩種場景的共同之處,在于它們都涉及型別推導

在模板f中,param的類型是推導得到的,而在var2的聲明語句中,var2的類型也是推導得到的。

因為萬能引用首先是個引用,所以初始化是必須的。萬能引用的初始化物會決定它代表的是個左值還是右值引用,如果初始化物是左值,萬能引用就會對應得到一個左值引用,同理,如果初始化物是右值,萬能引用就會對應得到一個右值引用。
對于作為函數形參的萬能引用而言,初始化物在調用處提供:

template<typename T> void f(T&& param);Widget w; f(w); //左值被傳遞給f,param的類型是Widget&,即左值引用f(std::move(w)); //右值被傳遞給f,param的類型是Widget&&,即右值引用

有一個需要注意的問題是,萬能引用除了要涉及型別推導,還有一個條件必須限定,就是必須要是“T&&”結構才行。
而類似

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

這樣的類型并不是萬能引用,僅僅只是一個右值引用。

而且,如果有const修飾也不可能成為萬能引用,比如:

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

那么,位于模板內是不是就一定就會涉及到型別推導呢? 還真不能保證。看以下示例:

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

以上是來自C++標準中vector類

這里的push_back的形參具備萬能引用的正確形式,但是在本示例中,并不涉及到類型推導。因為push_back作為vector本身的一部分,如果不存在特定的vector實例,則它也無從存在。該實例的具體類型完全決定了push_back的聲明類型。
如:

std::vector<Widget> v;

會導致std::vector模板具現化為如下實例:

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

現在就能看清楚push_back并未涉及到類型推導。

而vector中的另外一個函數卻涉及到了類型推導,如下:

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

以上emplace_back函數的形參 Args獨立于vector的型別形參T,所以Args必須在每次emplace_back被調用時進行推導。所以這里的args是個萬能引用。

最后,我們前面也提到過,auto變量也可以作為萬能引用。確切的說,聲明為auto&&的變量都是萬能引用,因為肯定涉及到型別推導并且肯定有正確的形式(“T&&”)

比如在C++14中 lambda表達式可以聲明auto&&形參。

結語

通過以上描述,終于搞清楚了萬能引用和右值引用的區別,那么回到文中最前面的問題,③⑤都是萬能引用,其他三個為右值引用,這下不會搞錯了。

總結如下:

  • 如果函數模板形參具備T&&型別,并且T的型別是推導而來,或如果對象使用auto&&聲明其類型,則該形參或對象就是萬能引用
  • 如果型別聲明不精確地具備type&&的形式,或者型別推導并未發生,則type&&就代表右值引用
  • 若采用右值來初始化萬能引用,就會得到一個右值引用,如果采用左值來初始化,則會得到一個左值引用。

參考:
Effective Modern C++
http://www.cplusplus.com/reference/

總結

以上是生活随笔為你收集整理的C++11:搞清楚万能引用和右值引用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。