废话不多说,先看代码
namespace _namp1
{
void func(const int& abc)
{
}
}
int main
{
_namp1::func(100);
}
现在问: abc的类型时啥,你肯定会脱口而出,废话,这不写着吗,const int&
好,现在将普通函数改成函数模板,试试?
namespace _namp1
{
template<typename T>
void func(const T& abc)
{
}
}
int main
{
_namp1::func(100);
}
ok,根据现在这行代码,T肯定是一个int类型,而abc可定是const int&
现在让我们记住万能引用的概念,和int是类型一样,万能引用也是一种类型,这句话先不要提出疑问,先记死。
再次强调,万能引用是一种类型!!!!!!!!!!!!!!!!!!!!!
再来看看另一组代码
namespace _namp1
{
void func(const int&& abc)
{
}
}
int main()
{
_namp1::func(100);
}
如果我这样写,编译器不会报错,因为我传递的是一个右值。
如果我传递的是一个左值,例如int i =100,我的VC++2017报如下错误 C2664 “void _namp1::func(const int &&)”: 无法将参数 1 从“int”转换为“const int &&”
所以可见右值引用不能绑定到左值上面去的。
我们换成函数模板试试:
namespace _namp1
{
template<typename T>
void func(T&& abc)
{
}
}
注意:上面代码中&&和T挨着,但是却和T一点关系都没有,不是T类型的一部分
这个时候,你不管传递左值还是右值都不会报错。
好了,万能引用全貌已经徐徐而出了:
1.万能引用必须满足必须是函数模板。
2.必须发生模板类型推导,函数模板形参长成如下样子:T&&。
万能引用也称为未定义引用,嗯,说的通俗易懂一点,就是既可以接左值,也可以接右值。
如果传进去一个左值abc会被推导为 int& 类型,传递右值的话会被推导成为int&&类型。
一个误区,T&& abc和右值引用没关系。
题目:
void func(int&& abc)
{
}
abc当然是右值引用,没有发生模板类型推导。
template<typename T>
void func(std::vector<T>&& abc)
{
}
abc也不是万能引用,必须是形如T&&
看下面一段代码:
template<typename T>
void func( T&& abc)
{
abc =100; //因为abc本身就是一个左值,所以不影响赋值。
return;
}
void main()
{
int i =10
func(i); //i会变成100
func(std::move(i)); //i变成右值,i还是100
}
由此可见,万能引用跟普通引用一样,不管你传进去的是左值还是右值,都会改变值。
万能引用资格的剥夺:
啥,万能引用资格还可以被剥夺,对的,如果你这样写
namespace _namp1
{
template<typename T>
void func(const T&& abc)
{
}
}
加入了const修饰符,万能引用的资格就退化了,变成了右值引用。
template<typename T>
class myClass
{
void myfunc(T&& abc);
}
向上面这种,也不是万能引用,因为这是一个类模板,没有发生函数模板类型推断。
template<typename T>
class myClass
{
template<typename T>
void myfunc(T&& abc); //除非这样写,发生了模板类型推断。
}