引用折疊
在現(xiàn)代 C++ 中一共有兩種引用類型,左值引用與右值引用,因此,在類型組合與推導(dǎo)的時候它們可能會出現(xiàn)四種組合。但是 C++ 不允許出現(xiàn)引用的引用,因此,需要一種機制來消除多重引用,這個機制就是引用折疊,引用折疊規(guī)則如下:

補充幾點:
- 引用折疊是針對通用引用的
- 當(dāng)左值作為參數(shù)傳入的時候模板參數(shù) T 推導(dǎo)為左值引用類型 T&
- 當(dāng)右值作為參數(shù)傳入的時候模板參數(shù) T 推導(dǎo)為值類型 T
- 然后再應(yīng)用引用折疊規(guī)則,推導(dǎo)出具體的參數(shù)類型
引用折疊使用場景
引用折疊發(fā)生的場景不多,主要有下面四種情形:
- T&& 模板類型推導(dǎo)
- auto&& 變量類型推導(dǎo),包括 Lambda 形參
- typedef / using T&& 別名聲明
- decltype(T)
代碼示例 :
#include
class X {};
// lvalues are encoded as lvalue reference type
// rvalues are encoded as non-reference value type
// T's type plus '&&' collapse to param's type
template void func(T &?m) {
if constexpr (std::is_lvalue_reference_v) {
std::cout << "T is lvalue reference\n";
// T deduced to 'T&'
// param's type is 'T& &&' collapse to 'T&'
} else {
std::cout << "T is non-reference\n";
// T deduced to 'T'
// param's type is 'T &&' collapse to 'T&&'
}
}
template class Y {
public:
typedef T &&rvalueRef_t0;
using rvalueRef_t1 = T &&;
rvalueRef_t1 y_;
};
int main() {
std::cout << std::boolalpha;
using std::cout, std::is_same_v;
// case 1: template instantiation (T&&)
X x1{};
func(x1); // T is lvalue reference
func(std::move(x1)); // T is non-reference
// case 2: auto&& variable
X x20{};
// lvalue cause auto deduced to 'X&'
// x21's type is 'X& &&' collapse to 'X&'
auto &&x21 = x20;
cout << is_same_v << '\n'; // true
// rvalue cause auto deduced to 'X'
// x22's type is 'X &&' collapse to 'X&&'
auto &&x22 = std::move(x20);
cout << is_same_v << '\n'; // true
// case 3: typedef and alias declarations
cout << is_same_v::rvalueRef_t0> << '\n'; // true
cout << is_same_v::rvalueRef_t1> << '\n'; // true
cout << is_same_v::rvalueRef_t0> << '\n'; // true
cout << is_same_v::rvalueRef_t1> << '\n'; // true
// case 4: decltype
cout << is_same_v::y_)> << '\n'; // true
return 0;
}
再談 std::forward
圖解 std::forward 與引用折疊的工作過程:

std::forward 對于左值,返回左值引用,對于右值,返回右值引用,保留類型修飾符
總結(jié)
- 理解引用折疊規(guī)則
- 了解引用折疊發(fā)生的場景
- 理解完美轉(zhuǎn)發(fā)的本質(zhì),以及引用折疊規(guī)則的應(yīng)用
|