一、左值与右值
1、最感性的认识
2、当然,左值也是可以在右边的
3、左值是可以被修改的,右值不能
4、当然取地址也是
生存周期一般左值会比右值的长
一般右值都计算时产生的无名临时对象,存在时间比较短
下面还有一种情况也要区分
二、左值引用和右值引用
左值引用:可以引用一个对象,有时候也可以绑定一个右值
右值引用:只能引用右值
1、左值引用
int a = 3;
int &p1 = a; // 左值引用
左值引用右值,将引发异常
但加上 const 就好了
2、右值引用
不能把左值绑定到右值,但使用 move 可以把左值转换右值就可以绑定
例如1
例如2
例如3
好了,理解上边的知识
接下来到引用折叠规则
三、引用折叠
怎么说好呢
来一段代码看看
#include <iostream>
using namespace std;
using lRef = int&; //左值引用
using rRef = int&&; //右值引用
int main(int argc, char **argv)
{
is_lvalue_reference<lRef &>::value ?
cout << "lRef & 左值引用" << endl :
cout << "lRef & 右值引用" << endl;
is_lvalue_reference<lRef &&>::value ?
cout << "lRef && 左值引用" << endl :
cout << "lRef && 右值引用" << endl;
is_rvalue_reference<rRef &>::value ?
cout << "rRef & 右值引用" << endl :
cout << "rRef & 左值引用" << endl;
is_rvalue_reference<rRef &&>::value ?
cout << "rRef && 右值引用" << endl :
cout << "rRef && 左值引用" << endl;
return 0;
}
调试结果
上边就是引用折叠规则
看着懵
没关系
看下图
由上图应该可以理解引用折叠规则了
可以看到只有都是右值引用的时候才是右值引用
当然只有一个右值引用的情况下自然而然也是右值引用
四、完美转发
完美转发是用来干嘛的呢
主要是用来
参数转发时
是左值传入还是右值传入
我们来一段测试代码
#include <iostream>
using namespace std;
template<typename T>
void Fun1(T& v)
{
cout << "左值引用调用" << v << endl;
}
template<typename T>
void Fun1(T&& v)
{
cout << "右值引用调用" << v <<endl;
}
template<typename T>
void Fun(T&& v)
{
Fun1(v);
}
int main(int argc, char **argv)
{
int a = 3;
Fun(a);
return 0;
}
主函数里给 Fun 传入 a,
根据上边知识
a 是一个左值,看调试结果是调用哪一个重载版本 Fun1
调试结果:发现和预想中的一样
接下来,我们更改为右值传入
int main(int argc, char **argv)
{
Fun(5);
return 0;
}
调试结果
这时,发现和想象中的不一样了
那么,为打目的我们要怎么做?
在 C++11 中提供了一个完美转发的函数 forward
还提供了一个 move 函数,用于把左值变右值的方法
forward 会根据引用折叠规则判定传入的是左值引用还是右值引用
好了,修改一下代码
template<typename T>
void Fun(T&& v)
{
Fun1(forward<T>(v));
}
再次调试结果
发现,达到目的啦
完美转发完整代码
#include <iostream>
using namespace std;
template<typename T>
void Fun1(T& v)
{
cout << "左值引用调用" << v << endl;
}
template<typename T>
void Fun1(T&& v)
{
cout << "右值引用调用" << v <<endl;
}
template<typename T>
void Fun(T&& v)
{
Fun1(forward<T>(v));
}
int main(int argc, char **argv)
{
int a = 1;
Fun(a);
Fun(move(a));
const int b = 2;
Fun(b);
Fun(move(b));
Fun(5);
return 0;
}
调试结果
五、_End
/