voidfun(int& a) { cout << "fun(int& a)" << endl; } voidfun(constint& a) { cout << "fun(const int& a)" << endl; } voidfun(int&& a) { cout << "fun(int&& a)" << endl; } voidtest(int&& a)//--与上一个例子最大的区别:不是模板函数! { fun(a); fun(std::forward<int>(a)); } intmain() { int a = 10; constint b = 20; //test(a); // 参数是左值,是无法调用test(int&& a)的,因为编译器规定:无法将‘右值参数’--‘绑定到左值’。 //test(std::move(b)); // 编译器提示:将"int &&”类型的引用绑定到"std:remove_reference_t<const int &>”类型的初始值设定项时,限定符被丢弃 --->意思是,警告我们不要这样做。这样会丢失b的const属性。 test(std::move(a)); // 但是我们知道,在平时的书写中,int a = 10; int b = a;这种写法是很普遍的,也就是说,虽然右值不能放在左值的位置上,但是左值是可以充当右值使用的,只不过是编译器规定了我们不能在调用函数时与把左值和右值混淆。 // 因为不能直接test(a);说明问题所在,所以我们std::move(a) } /* 运行结果 fun(int& a) fun(int&& a) 我们可以看到,在完美转发前,因为到了fun函数中,a又成为了有名变量,所以再次调用fun(a)退化为左值;而完美转发后,可以保持a的右值性。 */
这个结果,与上一个代码中的结果(完美转发后运行的结果依旧是fun(int& a)、fun(const int& a))一经对比,发现了问题:就是调用fac(a);fac(b);之前,由于fac是一个模板函数,而且参数类型很特殊!这是最关键的点,参数类型是T && tmp,这就要求,不管T是什么类型,不管要传入的实参是否是右值属性,我们都可以让其成功进入到此中,甚至他是一个左值(左值是可以充当右值使用的)。而模板机制中的T是会保留传入实参类型的所有信息的,包括const属性和左右值属性,比如int a = 10;的a是非常性左值,const int b = 20;的b是常性左值。所以,看上去tmp是一个右值,但是tmp的根源属性是外部a、b原来的属性。所以完美转发后的结果依旧是a的非常性左值int &,b的常性左值const int &。