我們先來看摺疊規則
引用摺疊規則
在C++中,引用摺疊規則的主要目的是為了保證在模板推導過程中,對於引數 T&&
能夠正確地推匯出其最終的引用型別,以便進行引數傳遞時的正確行為。下面是引用摺疊規則的總結:
-
左值引用摺疊:
T& &
摺疊為T&
T& &&
摺疊為T&
這意味著如果一個左值引用被再次引用,或者一個左值引用被右值引用引用,最終的結果仍然是左值引用。就是左值怎麼引用都是左值。
-
右值引用摺疊:
T&& &
摺疊為T&
T&& &&
摺疊為T&&
這意味著如果一個右值引用被左值引用引用,最終結果是左值引用;如果一個右值引用被右值引用引用,最終結果仍然是右值引用。
瞭解了摺疊規則後,我們來看個demo
template <typename F, typename T1, typename T2>
void flip2(F f, T1 &&t1, T2 &&t2)
{
f(t1, t2);
}
這個函式模板接受三個引數,並將t1和t2作為f的引數進行呼叫,給出f的實現
void gtemp(int&& v1, int& v2)
{
cout << v1 << " " << v2 << endl;
}
呼叫
int j = 99;
flip2(gtemp, 42, j);
cout << "j is " << j << endl;
得到報錯
error C2664: “void (int &&,int &)”: 無法將引數 1 從“T1”轉換為“int &&”
分析:42是一個右值物件,j是左值,在flip2中形參t1透過摺疊規則推導知型別為右值引用,t2是左值引用,但是將t1作為f的引數時,它依舊是作為一個左值來用的,因此gtemp也就是f呼叫明顯會出錯它的第一個引數型別為右值引用,也就是說flip2函式內部把外部實參42作為其他函式的引數傳遞時,將其的型別給“修改了”,從右值變為左值,這當然不是我們所希望的,那麼怎麼解決呢?
std::forward<>()函式就是用來保持型別不變的。
再看修改demo
template <typename F, typename T1, typename T2>
void flip2(F f, T1 &&t1, T2 &&t2)
{
f(std::forward<T1>(t1),std::forward<T2>(t2));
}
forward包含在utility庫裡,我們使用完美轉發函式使t1,t2保持型別與外部實參一致,也就是42(右值),j(int)因此程式正常執行。