C++ 禁止直接宣告「引用的引用」 (int& &r),但在模板實例化、auto 推導、typedef/using 別名、decltype 四種語境中,編譯器會產生引用的引用,隨即套用引用折疊規則化為單一引用。
| 組合 | 結果 | 口訣 |
|---|---|---|
T& & | T& | 有左值引用 → 左值引用 |
T& && | T& | |
T&& & | T& | |
T&& && | T&& | 全右值引用 → 右值引用 |
函數模板參數為 T&& 且 T 為模板參數時,稱為轉發參考 (C++20 正式術語) / 萬用引用。其類型推導編碼實參值類別:
T 推導為 U& → 參數型別 U& && 折疊為 U& (左值引用)。T 推導為 U → 參數型別 U&& (右值引用)。templatevoid func(T&& param); // 轉發參考 Widget w; func(w); // 左值 → T=Widget& → param: Widget& func(Widget{}); // 右值 → T=Widget → param: Widget&&
std::forward 只有在原始實參為右值時,將 arg (函數內部為左值) 轉換為右值;左值保持左值。
namespace std {
// C++11
template
T&& forward(typename remove_reference::type& arg) noexcept {
return static_cast(arg);
}
// C++14 簡化
template
T&& forward(remove_reference_t& arg) noexcept {
return static_cast(arg);
}
}
func(w),T 推導為 Widget&。forward(param) 實例化:Widget& forward(Widget& arg) { // remove_reference::type = Widget
return static_cast(arg); // T&& = Widget& && → 折疊為 Widget&
}
static_cast(arg) 無實際轉換,返回左值引用 → 左值。func(Widget{}),T 推導為 Widget。forward(param) 實例化:Widget&& forward(Widget& arg) { // remove_reference::type = Widget
return static_cast(arg); // T&& = Widget&&,無折疊
}
static_cast(arg) 將左值 arg 轉為右值引用 → 右值。func、forward。auto&& x = expr; 本質同模板推導。
auto&& r1 = lvalue; → auto 推導為 T& → T& && 折疊為 T&。auto&& r2 = rvalue; → auto 推導為 T → T&&。templatestruct Wrapper { using Ref = T&&; }; Wrapper ::Ref → int& && → 折疊為 int& (非右值引用!)
decltype((expr)) 為左值表達式產生 T&,參與折疊。std::forward 內部用 static_cast 配合 remove_reference,精準還原實參值類別。remove_reference_t、forward 簡化實作,語意不變。