<五>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));
}


posted @ 2023-05-04 06:32  Hello_Bugs  阅读(50)  评论(0编辑  收藏  举报