C++ 副程式的 const左右值引用 的完美轉發
tags: C++ Concept2
四種不同屬性的函式
已知存在著四種屬性
- lvalue
- lvalue const
- rvalue
- rvalue const
他們分別呼叫的副程式參數長這個樣子
void fun(int & i){
cout << "fun L" << endl;
}
void fun(int const & i){
cout << "fun L const" << endl;
}
void fun(int && i){
cout << "fun R" << endl;
}
void fun(int const && i){
cout << "fun R const" << endl;
}
如此宣告我們可以統一使用 fun() 這個名稱呼叫四種不同的函式,分別是這樣呼叫
int a=0;
int const b=0;
fun(a);
fun(b);
fun(move(a));
fun(move(b));
函式轉發
如果你想要用另一個副程式來呼叫這個 fun() 藉此組合更多的功能可能會遇到一些問題
- const 與 non-const區分
- 左值與右值區分
- 右值進來有了名字變成左值
const 與非 const
可以試著重載const藉此可以同時引入兩種版本
template<class T>
void tran(T const & t){
fun(t);
}
不過如此一來將導致你沒有辦法修改內容,也無從判斷原本是否是const
可以透過&&達到正確的結果
可以透過&&達到正確的結果
template<class T>
void tran(T && t){
fun(t);
}
如此由 template 解決引數是否有 const,由 && 解決引數是左值還是右值。
消除名字
不過仍然有一個問題,參數本身是帶有名字的再引入的時候有了名字就變成左值
可以透過
該是右值就還原右值,該是左值則保持左值
可以透過
forward<T>(t)
消除名字,獲取原本的屬性,該是右值就還原右值,該是左值則保持左值
template<class T>
void tran(T && t){
fun(forward<T>(t));
}
如此一來我們就可以好像換了一個別名似的,用第二個名字自由的操作,可以在函式內加上一些功能,增加代碼的重複性。
template<class T>
void tran(T && t){
// 其他功能
fun(forward<T>(t));
}
fun();
tran();
需要 fun() 時使用他,需要fun() 加上一額外的功能使用 tran() ,並可將重複的代寫在一起
為什麼不是使用 move() 語意即可?
確實可以透過move()協助我們呼叫右值引數的函式,但是無從得知原本的屬性是什麼,不管進入函式的是左值還是右值move()一律將其轉為右值;相較於forward()這個能夠還原原本的屬性,原本屬性是左值,出來就是還是左值。
如果要使用 move() 解決那至少也要存在著2個函式才可以解決,一個呼叫左值一個呼叫右值,這是因為無法得知原本屬性,只能給使用者自己判斷。
template<class T>
void tran1(T & t){
fun(t);
}
template<class T>
void tran2(T && t){
fun(move(t));
}
參考代碼
/*****************************************************************
Name :
Date : 2017/04/07
By : CharlotteHonG
Final: 2017/04/07
*****************************************************************/
#include <iostream>
using namespace std;
void fun(int & i){
cout << "fun L" << endl;
}
void fun(int const & i){
cout << "fun L const" << endl;
}
void fun(int && i){
cout << "fun R" << endl;
}
void fun(int const && i){
cout << "fun R const" << endl;
}
template<class T>
void tran(T && t){
fun(forward<T>(t));
}
// template 解決了 const 與 non-constt 的問題,可以還原原本屬性
// && 解決了 LR 屬性問題,可以還原原本左右值屬性
// move提供使用者選擇,可以選擇要叫左值還是右值的函式
// forward 解決了引入的右值有了名字變成左值的問題
/*==============================================================*/
int main(int argc, char const *argv[]){
int a=0;
int const b=0;
// fun(a);
// fun(b);
// fun(move(a));
// fun(move(b));
tran(a);
tran(b);
tran(move(a));
tran(move(b));
return 0;
}
/*==============================================================*/
沒有留言:
張貼留言