C++的引用折疊


引用折疊:創建引用的引用時(如模板參數、類型別名)會造成引用折疊,折疊規則如下:
1.
&+&->&
&&+&->&
&+&&->&
2.&&+&&->&&
3.左值(非引用)+&&(模板形參的)->&,實際上是:編譯器會自己在模板形參類型前加&,這樣就變成了:&+&&,依據前面的規則還是會折疊為&。
注意:第3種情況只適用於&&形參的模板函數,不適合普通函數!
例子:
template<typename T> T ff(T&& x){
    return x;
}
int fff(int &&x){
    return x;
}
int main()
{
    int i=1;
    cout<<ff(i);
    cout<<fff(i);
    getchar();
}
其中fff(i)的調用是錯誤的!因為傳遞了一個左值給一個參數為右值引用的函數。ff(i)的調用是正確的,通過引用折疊,實際調用的函數是int ff(int&);

 

例子:

 

template<typename T> T ff(T && x){
    return x;
}
int main()
{
    int i=1;
    int &j=i;
    int&& k=move(i);
    int p[10];
    cout<<ff(i);
    cout<<ff(5);
    cout<<ff(p);
    cout<<ff(j);
    cout<<ff(move(i));
    getchar();
}
 
          
        

引用折疊了:i是普通int變量,普通左值按規則3,得到&

 

 

5是右值,沒有引用折疊

 

 

 

 p為int [10]類型,但這里由於符合上面第三條,加&得到int (&)[10],即一個int[10]數組的引用的類型。然后進行引用折疊:int (&)[10]+&&->int(&)[10],還是自己。

如果把函數改成這樣:

template<typename T> T ff(T x){
    return x;
}
int main()
{
    int i=1;
    int &j=i;
    int&& k=move(i);
    int p[10];
    cout<<ff(i);
    cout<<ff(5);
    cout<<ff(p);
    cout<<ff(j);
    cout<<ff(move(i));
    getchar();
}

即f的參數不再是右值引用,那么就不存在引用折疊問題了,並且數組p傳入f函數時,會自動轉為int*類型:

 

 另一個例子:

typedef const int T;
typedef T& TR;
typedef T&& TRR;

void JudgeType()
{
    cout << "lvalue_ref_type?: " << is_lvalue_reference<TR>::value << endl;  // 1
    cout << "rvalue_ref_type?: " << is_rvalue_reference<TR>::value << endl;  // 0

    cout << "lvalue_ref_type?: " << is_lvalue_reference<TR&>::value << endl; // 1
    cout << "rvalue_ref_type?: " << is_rvalue_reference<TR&>::value << endl; // 0

    cout << "lvalue_ref_type?: " << is_lvalue_reference<TR&&>::value << endl; // 1
    cout << "rvalue_ref_type?: " << is_rvalue_reference<TR&&>::value << endl; // 0

    cout << "lvalue_ref_type?: " << is_lvalue_reference<TRR>::value << endl;  // 0
    cout << "rvalue_ref_type?: " << is_rvalue_reference<TRR>::value << endl;  // 1

    cout << "lvalue_ref_type?: " << is_lvalue_reference<TRR&>::value << endl; // 1
    cout << "rvalue_ref_type?: " << is_rvalue_reference<TRR&>::value << endl; // 0

    cout << "lvalue_ref_type?: " << is_lvalue_reference<TRR&&>::value << endl; // 0
    cout << "rvalue_ref_type?: " << is_rvalue_reference<TRR&&>::value << endl; // 1
}

int main()
{
    JudgeType();
    system("pause");
}

 

 

一個暫時不懂的問題:

template<typename T> T ff(T&& x){
    return x;
}
template<typename T> T ff(const T& x){
    return x;
}
int main()
{
    int i=1;
    int& j=i;
    const int k=1;
    const int& l=i;
    cout<<ff(i);//調用ff(T&&)並折疊為T(&):符合左值(非引用)+&&,先加&,變成&+&&->&
    cout<<ff(j);//調用ff(T&&)並折疊為T(&):符合&+&&->&
    cout<<ff(5);//調用T(&&)
    cout<<ff(k);//調用T(const T&)
    cout<<ff(l);//調用T(const T&)
    getchar();
}

目前我只能認為只要能匹配&&的(通過引用折疊匹配的也算),都去匹配&&版本了。。

帶const的都匹配不了&&,只能匹配const T&

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM