万能引用(universal reference/forwarding reference:转发引用)
1类型区别基本含义
template<typename T>
void func(const T& abc){}
func(10); //T:int,abc=const int&
2universal reference/万能引用/未定义引用基本认识
- 结论:万能引用是一种类型
- 右值引用(全程:右值引用类型)是用&&表示,右值引用绑定在右值上
void myfunc(int&& tmpv) {
cout << tmpv << endl;
}
int&& rv = 1000; //rv是右值引用
myfunc(10);
int i = 100; //i是左值
//nmsp1::myfunc(i); //编译出错,右值引用不能绑定左值
如果我们想一个函数既能接收左值引用又能接收右值引用
template<typename T>
void myfunc1(T&& tmpv) {
//注意 &&是属于tmprv类型的一部分,不是T类型的一部分(&&和T)没有关系
cout << tmpv << endl;
//万能引用能接收左值和右值
//万能引用也称为未定义类型
}
myfunc1(10);
myfunc1(i);
万能引用离不开两种语境
-
必须是函数模板
-
必须是发生模板类型推断并且函数模板形参长这样:T&&;
-
如果参数传递了一个整型左值传递给形参,tmprv的类型最终会被推断为int&类型
-
如果参数传递了一个整型右值传递给形参,tmprv的类型最终会被推断为int&&类型
题目:
void func(int&& param) {...}//右值引用
template<typename T>
void func(T&& param){...}//是万能引用
std::move
把左值转换为右值
template<typename T>
void func2(std::vector<T>&& param) {}//右值引用
std::vector<int> aa = { 1 };
//nmsp1::func2(aa);//错误:无法将左值转换为右值
nmsp1::func2(std::move(aa) );//转换为右值
什么情况才是万能引用
-
一个是函数模板中用作函数参数的类型推断(参数中主要涉及类型推断)T&&
-
auto&& tmpvalue=…也是万能引用
-
其他情况的&&的情形的都是右值引用
template<typename T>
void myfunc3(T&& tmpv) {//
tmpv = 12;
//不管tmpv的类型是左值引用还是右值引用,都可以给tmprv赋值,因为tmprv本身是个左值
cout << tmpv << endl;
}
myfunc3(i);
//左值被传递,因为tmprv是个左值引用,也就是int&,最终i=12
i = 200;
myfunc3(std::move(i));
//右值被传递,因此是tmprv是个右值引用,也就是int&&,最终i变为12
万能引用资格的剥夺与辨认
- 剥夺,const会剥夺一个引用成为万能引用的资格,被打回右值成为右值引用
template<typename T>
void myfunc4(const T&& tmpv) {//有const修饰
cout << tmpv << endl;
}
//nmsp1::myfunc4(i);错误,只能传递右值
myfunc4(std::move(i));
- 辨认
template<typename T1>
class mytest {
public:
void testfunc(T1&& x){}
//这个不是万能引用,
template<typename T2>
void testfunc2(T2&& x) {}//x类型是万能引用类型
};
nmsp2::mytest<int> mc;
//mc.testfunc(i);//错误
mc.testfunc(std::move(i));
//因为testfunc成员函数本身没有涉及到类型推断
mc.testfunc2(i);
mc.testfunc2(2);