<四>move移动语义和forward类型转发
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));
}