文章目录

  • 万能引用
  • 引用折叠
  • 右值变左值的情况

万能引用

左值引用只能引用左值,右值引用只能引用右值。
但是对于一个函数我们有时候并不清楚传入的参数是左值还是右值,这时候就需要写两个同名的函数重载,而万能引用的出现解决了这个问题。

万能引用需要和模板配合使用

template<class T>
void f(T&& param);

如果一个变量或者参数被声明为T&&,其中T是被推导的类型,那这个变量或者参数就是一个万能引用。
当传入的参数是左值的时候,函数就会实例化出一个左值引用的函数,当传入的参数是右值的时候,函数就会实例化出一个右值引用的函数。

以下这种形式并不是万能引用:

template<typename T>
void f(std::vector<T>&& param);     // “&&” means rvalue referencetemplate<typename T>
void f(const T&& param);               // “&&” means rvalue reference

引用折叠

使用万能引用或者在其他类型推导的场景时会遇到一个问题,那就是我们传入的参数是一个引用类型,而接收的函数模板也是引用类型,这就会出现引用的引用。例如当模板参数T为Vector&或Vector&&,模板函数形参为T&&时,展开后变成Vector& &&或者Vector&&。

引用折叠 & &&
& & &
&& & &&
  • 如果传递过去的参数是左值,T 的推导结果是左值引用,也就是T&,那 T&&& 的结果仍然是左值引用——即T&,&& 折叠成了&
  • 如果传递过去的参数是右值,T 的推导结果是右值引用,但其推导类型为T(而不是T&&),最终T&&自然就是右值引用。

这也就是万能引用既能引用右值也能引用左值的原因。

其他类型推导的情况,比如auto:

Widget&& var1 = someWidget;      // var1 is of type Widget&& auto&& var2 = var1;              // var2 is of type Widget&

var1 的类型是 Widget&&,但是在推导 var2 类型的时候被忽略了其引用成分,var1 这时候就被当做 Widget。
又因为var1是一个左值,其在初始化var2时,auto会自动推导var2类型为Widget&:

Widget& && var2 = var1;

而在引用折叠之后,就变成了:

Widget& var2 = var1;

右值变左值的情况

当我们使用了万能引用时,即使可以同时匹配左值、右值,但需要转发参数给其他函数时,会丢失引用性质。
这主要是因为形参是个左值,从而无法判断到底匹配的是个左值还是右值。

因为右值是无法取地址的,而一旦这个右值被右值引用,该引用可以被取地址,所以此时这个右值引用被当做是左值。也就是说,右值引用本身就是个左值,只是他可以绑定右值。

void f(int& param)
{cout << "int&" << endl;
}void f(int&& param)
{cout << "int&" << endl;
}int main() {int&& r1 = 10;cout << &r1 << endl;//右值引用可以取地址,右值引用是左值// cout << &10 << endl;//错误f(r1);//int&
}
void Fun(int& x) { cout << "lvalue ref" << endl; }
void Fun(int&& x) { cout << "rvalue ref" << endl; }
void Fun(const int& x) { cout << "const lvalue ref" << endl; }
void Fun(const int&& x) { cout << "const rvalue ref" << endl; }
template<class T>
void PerfectForward(T&& t)
{ //这里的t是一个左值,因此即使t为右值引用,依然会调用左值引用的FunFun(t);
}
int main()
{PerfectForward(10); int a;PerfectForward(a); PerfectForward(std::move(a)); const int b = 8;PerfectForward(b); PerfectForward(std::move(b)); return 0;
}

这也就是完美转发需要解决的问题。
值得注意的是,如果需要多次转发参数,每次转发都要使用完美转发。

void Fun2(int& x)
{ cout << "Fun2 lvalue ref" << endl;
}
void Fun2(int&& x)
{cout << "Fun2  rvalue ref" << endl;
}
void Fun1(int& x)
{cout << "Fun1 lvalue ref" << endl;Fun2(std::forward<int>(x));
}
void Fun1(int&& x)
{cout << "Fun1 rvalue ref" << endl;Fun2(std::forward<int>(x));
}
template<class T>
void PerfectForward(T&& t)
{Fun1(std::forward<T>(t));
}
int main()
{PerfectForward(10);int a;PerfectForward(a); return 0;
}


参考资料:
透彻理解C++11 移动语义:右值、右值引用、std::move、std::forward
现代C++之万能引用、完美转发、引用折叠(万字长文)
关于C++的引用

万能引用,引用折叠,右值变左值的情况相关推荐

  1. 左值、右值、左值引用和右值引用

    文章目录 左值和右值 什么是左值和右值? 举例说明 程序分析 左值引用和右值引用 什么是左值引用和右值引用? 左值引用 右值引用 (important!!!) 左值和右值的转换 左值变右值 右值变左值 ...

  2. [c++]-c++中的左值和右值、左值引用和右值引用、万能引用和引用折叠及完美转发

    1.左值和右值 1.1左值和右值定义 在c++中,左值是一个指向内存的东西,换句话来讲,左值有地址,保存在内存中,右值则为不指向任何地方东西,即不在内存中占有确定位置.一般来说,右值是暂时和短暂的,而 ...

  3. java左值与右值问题_[C++11]左值、右值、左值引用、右值引用小结

    左值和右值 左值:指表达式结束后依然存在的持久对象,可以取地址,具名变量或对象 右值:表达式结束后就不再存在的临时对象,不可以取地址,没有名字. 比如 int a = b + c;,a 就是一个左值, ...

  4. [C++11]左值、右值、左值引用、右值引用小结

    左值和右值 左值:指表达式结束后依然存在的持久对象,可以取地址,具名变量或对象 右值:表达式结束后就不再存在的临时对象,不可以取地址,没有名字. 比如 int a = b + c;,a 就是一个左值, ...

  5. C++面试 左值、右值、左值引用、右值引用

    1.左值和右值 左值(left-values),缩写:lvalues  ,located value 可定位值,其含义是可以明确其存放地址的值,更确切说对其的使用是基于地址 右值(right-valu ...

  6. C++左值、右值、左值引用、右值引用

    左值(lvalue)和右值(rvalue) 左值(lvalue):locator value,存储在内存中.有明确的的地址(可寻址)的数据 能够取地址,有名字的值就是左值 //左值引用 int a=1 ...

  7. 详解 C++ 左值、右值、左值引用以及右值引用

    文章目录 一.左值和右值 1.左值 2.右值 3.总结 二.左值引用和右值引用 1.左值引用 2.右值引用 3.对比与总结 三.左值引用的使用场景及实际意义 1.使用场景 2.实际意义 3.短板 四. ...

  8. C++/C++11中左值、左值引用、右值、右值引用的使用

    C++的表达式要不然是右值(rvalue),要不然就是左值(lvalue).这两个名词是从C语言继承过来的,原本是为了帮助记忆:左值可以位于赋值语句的左侧,右值则不能. 在C++语言中,二者的区别就没 ...

  9. 39.左值、左值引用、右值、右值引用

    1.左值和右值的概念 左值是可以放在赋值号左边可以被赋值的值:左值必须要在内存中有实体:          右值当在赋值号右边取出值赋给其他变量的值:右值可以在内存也可以在CPU寄存器.       ...

最新文章

  1. 我在谷歌实习时发现了一个模型 bug,于是有了这篇 ACL
  2. Ubuntu14.04安装JDK
  3. Mysql 错误 Code: 1093. You can't specify target table for update in FROM clause
  4. UVA 11292 The Dragon of 贪心
  5. mysql备份文件0kb_Oracle 数据文件大小为0kb或者文件丢失恢复
  6. QT-Linux开发环境的搭建
  7. spark 算子例子_Spark性能调优方法
  8. 计算机二级考试python_全国计算机等级考试考试大纲(2018年版)
  9. 【蓝桥杯单片机】实战训练:基于15单片机的距离测试及电压数据采集响应系统(超声波测距、上位机、DAC输出)
  10. 本周进步要点(第3周1.9--1.15)
  11. 正则表达式及常用大全
  12. Android聊天软件开发(基于网易云IM即时通讯)——发送文本消息(四)
  13. 【解决】WPS 2019 Windows版如何更换序列号
  14. python 基础-----list查找重复值
  15. 带你走进多媒体世界:视频文件是怎么播放出来的
  16. html给图片添加边框
  17. 【系统架构】-什么是MDA架构、ADL、DSSA
  18. 使用PIXI制作简单canvas逐帧动画的心得
  19. Storm - 事务管理
  20. 先有鸡还是先有蛋的争论

热门文章

  1. 多条Qt开发常见问题及解决方法汇总
  2. php 图片加水印文字水印
  3. 微信小程序右上角胶囊按钮尺寸
  4. 我的世界神秘时代安卓java版_我的世界神秘时代MOD
  5. 【初等数论】【转载】夜深人静写算法(五) - 初等数论
  6. 物流基础知识(十七)
  7. 基于Google 验证器 实现内网的双因素认证
  8. 想转行人工智能?机会来了!!!
  9. yolov5 【v4.0】用自有数据集训练结果大比拼【5s,5m,5l,5x,5shpy】
  10. ios 调整麦克风音量_ios 调整麦克风音量_如何在ios 7中获得麦克风音量?