亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++11 模板參數(shù)的“右值引用”是轉(zhuǎn)發(fā)引用嗎

 更新時(shí)間:2020年05月25日 14:37:20   作者:jerry_fuyi  
這篇文章主要介紹了C++11 模板參數(shù)的“右值引用”是轉(zhuǎn)發(fā)引用嗎,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

在C++11中,&&不再只有邏輯與的含義,還可能是右值引用:

void f(int&& i);

但也不盡然,&&還可能是轉(zhuǎn)發(fā)引用:

template<typename T>
void g(T&& obj);

“轉(zhuǎn)發(fā)引用”(forwarding reference)舊稱“通用引用”(universal reference),它的“通用”之處在于你可以拿一個(gè)左值綁定給轉(zhuǎn)發(fā)引用,但不能給右值引用:

void f(int&& i) { }

template<typename T>
void g(T&& obj) { }

int main()
{
  int n = 2;
  f(1);
// f(n); // error
  g(1);
  g(n);
}

一個(gè)函數(shù)的參數(shù)要想成為轉(zhuǎn)發(fā)引用,必須滿足:

  • 參數(shù)類型為T&&,沒有const或volatile;
  • T必須是該函數(shù)的模板參數(shù)。

換言之,以下函數(shù)的參數(shù)都不是轉(zhuǎn)發(fā)引用:

template<typename T>
void f(const T&&);
template<typename T>
void g(typename std::remove_reference<T>&&);
template<typename T>
class A
{
  template<typename U>
  void h(T&&, const U&);
};

另一種情況是auto&&變量也可以成為轉(zhuǎn)發(fā)引用:

auto&& vec = foo();

所以寫范圍for循環(huán)的最好方法是用auto&&:

std::vector<int> vec;
for (auto&& i : vec)
{
  // ...
}

有一個(gè)例外,當(dāng)auto&&右邊是初始化列表,如auto&& l = {1, 2, 3};時(shí),該變量為std::initializer_list<int>&&類型。

轉(zhuǎn)發(fā)引用,是用來(lái)轉(zhuǎn)發(fā)的。只有當(dāng)你的意圖是轉(zhuǎn)發(fā)參數(shù)時(shí),才寫轉(zhuǎn)發(fā)引用T&&,否則最好把const T&和T&&寫成重載(如果需要的話還可以寫T&,還有不常用的const T&&;其中T是具體類型而非模板參數(shù))。

轉(zhuǎn)發(fā)一個(gè)轉(zhuǎn)發(fā)引用需要用std::forward,定義在<utility>中:


調(diào)用g有幾種可能的參數(shù):

  • int i = 1; g(i);,T為int&,調(diào)用g(int&);
  • const int j = 2; g(j);,T為const int&,調(diào)用g(const int&);
  • int k = 3; g(std::move(k));或g(4);,T為int(不是int&&哦?。?,調(diào)用g(int&&)。

你也許會(huì)疑惑,為什么std::move不需要<T>而std::forward需要呢?這得從std::forward的簽名說(shuō)起:

template<typename T>
constexpr T&& forward(std::remove_reference_t<T>&) noexcept;
template<typename T>
constexpr T&& forward(std::remove_reference_t<T>&&) noexcept;

調(diào)用std::forward時(shí),編譯器無(wú)法根據(jù)std::remove_reference_t<T>反推出T,從而實(shí)例化函數(shù)模板,因此<T>需要手動(dòng)指明。

但是這并沒有從根本上回答問(wèn)題,或者可以進(jìn)一步引出新的問(wèn)題——為什么std::forward的參數(shù)不定義成T&&呢?

原因很簡(jiǎn)單,T&&會(huì)把T&、const T&、T&&和const T&&(以及對(duì)應(yīng)的volatile)都吃掉,有了T&&以后,再寫T&也沒用。

且慢,T&&參數(shù)在傳入函數(shù)是會(huì)匹配到T&&嗎?

#include <iostream>
#include <utility>

void foo(int&)
{
  std::cout << "int&" << std::endl;
}

void foo(const int&)
{
  std::cout << "const int&" << std::endl;
}

void foo(int&&)
{
  std::cout << "int&&" << std::endl;
}

void bar(int&& i)
{
  foo(i);
}

int main()
{
  int i;
  bar(std::move(i));
}

不會(huì)!程序輸出int&。在函數(shù)bar中,i是一個(gè)左值,其類型為int的右值引用。更直接一點(diǎn),它有名字,所以它是左值。

因此,如果std::forward沒有手動(dòng)指定的模板參數(shù),它將不能區(qū)分T&和T&&——那將是“糟糕轉(zhuǎn)發(fā)”,而不是“完美轉(zhuǎn)發(fā)”了。

最后分析一下std::forward的實(shí)現(xiàn),以下代碼來(lái)自libstdc++:

template<typename _Tp>
 constexpr _Tp&&
 forward(typename std::remove_reference<_Tp>::type& __t) noexcept
 { return static_cast<_Tp&&>(__t); }

template<typename _Tp>
 constexpr _Tp&&
 forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
 {
  static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument"
         " substituting _Tp is an lvalue reference type");
  return static_cast<_Tp&&>(__t);
 }

  • 當(dāng)轉(zhuǎn)發(fā)引用T&& obj綁定左值int&時(shí),匹配第一個(gè)重載,_Tp即T為int&,返回類型_Tp&&為int&(引用折疊:& &、& &&、&& &都折疊為&,只有&& &&折疊為&&);
  • const int&同理;
  • 當(dāng)轉(zhuǎn)發(fā)引用綁定右值int&&時(shí),匹配第二個(gè)重載,_Tp為int,返回類型為int&&;
  • const int&&同理。

綜上,std::forward能完美轉(zhuǎn)發(fā)。

程序員總是要在Stack Overflow上撞撞墻才能學(xué)會(huì)一點(diǎn)東西。

到此這篇關(guān)于C++11 模板參數(shù)的“右值引用”是轉(zhuǎn)發(fā)引用嗎的文章就介紹到這了,更多相關(guān)C++11 右值引用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論