move : 移動語義,得到右值類型 forward:類型轉發,能夠識別左值和右值類型 只有兩種形式的引用,左值引用和右值引用,萬能引用不是一種引用類型,它存在於模板的引用摺疊情況,但是能夠接受左值和右值 區分左值和右值得一個簡單方式就是能不能取地址 一個右值一旦有名字那麼就變成了左值 #inclu ...
move : 移動語義,得到右值類型
forward:類型轉發,能夠識別左值和右值類型
只有兩種形式的引用,左值引用和右值引用,萬能引用不是一種引用類型,它存在於模板的引用摺疊情況,但是能夠接受左值和右值
區分左值和右值得一個簡單方式就是能不能取地址
一個右值一旦有名字那麼就變成了左值
#include <iostream>
using namespace std;
void process(int & i) {
std::cout << i << " lvalue" << std::endl;
}
void process(int && i) {
std::cout << i << " r value" << std::endl;
}
template<typename T>
void test(T && v) { //這裡的&& 表示萬能引用,既能接受左值也能接受右值
process(v);
}
int main() {
int i = 100;
test(i);
test(200);
system("pause");
return 0;
}
上面的運行結果 我們發現 test(i); 和 test(200); 最後都調用了 void process(int & i) 左值形參,
test(T && v) 接受test(i)的時候,是用左值去接, 接受test(200)的時候,使用右值去接,
其中有一點右值本身是一個左值類型(如何理解?右值本身是有地址有名稱的,所以他本身就可以取地址了,他是一個左值)
所以函數形參一定是個左值,他有名字,有空間了,變成了具名對象,200傳過去後變成了一個左值.
200 傳入 test後就變成了一個左值了,進入了test 函數後沒有保留好原始信息,所以 process(v); 就都調用了void process(int & i) 左值形參,
這個我叫做 不完美轉發
但是我希望 在test 函數內任然能夠保留原始信息,原始的是左值繼續保留左值,原始是右值就繼續保留右值, 如何實現呢? 完美轉發
引用摺疊技術
形參 是 T && v ,在模板函數形參,兩個引用 在一起會引發引用摺疊, 有一個左值引用 最後是=》左值, 兩個都是右值 最後是=>右值
即 test(i) + void test(T && v) => T & && i => 左值
即 test(200) + void test(T && v) => T && && 200 => 右值
所以將 函數形參寫成 &&
//模板實例化過程中出現這種情況就會發生引用摺疊,如果任一尹永偉左值引用,那麼結果就是左值引用,
//如果兩個都是右值引用,那麼結果為右值引用
template<typename T>
void test2(T && v) {
std::cout <<"is int & " << std::is_same_v<T, int &> << std::endl;
std::cout << "is int " << std::is_same_v<T, int > << std::endl;
}
int main() {
int i = 100;
test2(i);
test2(200);
system("pause");
return 0;
}
template<typename T>
void test2(T && v) {
std::cout <<"is int & "<< std::is_same_v<T, int &> << std::endl;
std::cout << "is int " << std::is_same_v<T, int > << std::endl;
}
int main() {
int i = 100;
test2(i);
test2(200);
system("pause");
return 0;
}
test2(i) 調用模板會實例化出如下模板
void test2(int & && v) {
std::cout <<"is int & "<< std::is_same_v<T, int &> << std::endl;
std::cout << "is int " << std::is_same_v<T, int > << std::endl;
}
test2(200) 調用模板會實例化出如下模板
void test2(int && v) {
std::cout <<"is int & " << std::is_same_v<T, int &> << std::endl;
std::cout << "is int " << std::is_same_v<T, int > << std::endl;
}
上面兩個實例化出來的模板,形參根據引用摺疊技術
void test2(int & && v) =》void test2(int & v)
void test2(int && v) =》void test2(int && v)
即 如果 test2(i) 那麼模板中的 T 就是 int &
如果 test2(200 ) 那麼模板中的 T 就是 int
所以 下麵的代碼
template<typename T>
void test(T && v) { //這裡的&& 表示萬能引用,既能接受左值也能接受右值
process(v);
}
我們這裡這麼改一下
template<typename T>
void test(T && v) { //這裡的&& 表示萬能引用,既能接受左值也能接受右值
process(static_cast<T&&>(v));
// test(i) => process( static_cast<int & &&>(v)); => process( static_cast<int & >(v));
// test(200)=> process( static_cast<int &&>(v)); => process( static_cast<int && >(v));
}