前言

我们通过一个问题来进入今天的话题:
1.形如 “type&&” 的结构,就是右值引用吗?
2.以下哪些属于右值引用?

  • void fun(Widget && param);
  • Widget && var1= Widget();
  • auto && var2 = var1;
  • template<typename T> void f(std::vector<T>&& param);
  • template<typename T> void f(T&& param);

带着以上的问题,我们来看一下到底type&&的结构包含了哪些含义。

正文

实际上,type&& 有两种不同的含义。
其中一种就是 右值引用。它仅仅会绑定右值,用于识别出可移对象。
另外一种含义,则表示既可以是右值引用,也可以是左值引用。这种双重特性使其可以绑定到右值,也可以绑定到左值。还可以绑定到const对象或非const对象,以及volatile对象,甚至可以绑定那些既带有const又带有volatile的对象,拥有很强的灵活性,这就是万能引用

那么,既然以上两种含义都是 type&& 结构,那么如何来区分二者呢?

万能引用

万能引用通常会在两种场景现身:函数模板的形参 和 auto声明。
示例如下:

template<typename T>
void f(T&& param);   //param是个万能引用
auto && var2 = var1;

以上两种场景的共同之处,在于它们都涉及型别推导

在模板f中,param的类型是推导得到的,而在var2的声明语句中,var2的类型也是推导得到的。

因为万能引用首先是个引用,所以初始化是必须的。万能引用的初始化物会决定它代表的是个左值还是右值引用,如果初始化物是左值,万能引用就会对应得到一个左值引用,同理,如果初始化物是右值,万能引用就会对应得到一个右值引用。
对于作为函数形参的万能引用而言,初始化物在调用处提供:

template<typename T>
void f(T&& param);Widget w;
f(w);             //左值被传递给f,param的类型是Widget&,即左值引用f(std::move(w));  //右值被传递给f,param的类型是Widget&&,即右值引用

有一个需要注意的问题是,万能引用除了要涉及型别推导,还有一个条件必须限定,就是必须要是“T&&”结构才行。
而类似

template<typename T>
void f(std::vector<T>&& param);   //param是右值引用

这样的类型并不是万能引用,仅仅只是一个右值引用。

而且,如果有const修饰也不可能成为万能引用,比如:

template<typename T>
void f(const T&& param);  //param是右值引用

那么,位于模板内是不是就一定就会涉及到型别推导呢? 还真不能保证。看以下示例:

template <class T,class Allocator = allocator<T>>
class vector{public:void push_back(T&& x);...
};

以上是来自C++标准中vector类

这里的push_back的形参具备万能引用的正确形式,但是在本示例中,并不涉及到类型推导。因为push_back作为vector本身的一部分,如果不存在特定的vector实例,则它也无从存在。该实例的具体类型完全决定了push_back的声明类型。
如:

std::vector<Widget> v;

会导致std::vector模板具现化为如下实例:

template <class Widget,class Allocator = allocator<Widget>>
class vector{public:void push_back(Widget&& x);  //右值引用...
};

现在就能看清楚push_back并未涉及到类型推导。

而vector中的另外一个函数却涉及到了类型推导,如下:

template <class T,class Allocator = allocator<T>>
class vector{public:template<class... Args>void emplace_back(Args&&... args);...
};

以上emplace_back函数的形参 Args独立于vector的型别形参T,所以Args必须在每次emplace_back被调用时进行推导。所以这里的args是个万能引用。

最后,我们前面也提到过,auto变量也可以作为万能引用。确切的说,声明为auto&&的变量都是万能引用,因为肯定涉及到型别推导并且肯定有正确的形式(“T&&”)

比如在C++14中 lambda表达式可以声明auto&&形参。

结语

通过以上描述,终于搞清楚了万能引用和右值引用的区别,那么回到文中最前面的问题,③⑤都是万能引用,其他三个为右值引用,这下不会搞错了。

总结如下:

  • 如果函数模板形参具备T&&型别,并且T的型别是推导而来,或如果对象使用auto&&声明其类型,则该形参或对象就是万能引用
  • 如果型别声明不精确地具备type&&的形式,或者型别推导并未发生,则type&&就代表右值引用
  • 若采用右值来初始化万能引用,就会得到一个右值引用,如果采用左值来初始化,则会得到一个左值引用。

参考:
Effective Modern C++
http://www.cplusplus.com/reference/

C++11:搞清楚万能引用和右值引用相关推荐

  1. 【C++11】左值引用和右值引用

    目录 一.新的类功能 1.新的默认成员函数 2.类成员变量初始化 3.强制生成默认函数的关键字default 4.禁止生成默认函数的关键字delete 二.左值和右值 1.左值和左值引用 2.右值和右 ...

  2. C++11新特性(一)右值引用

    @ 一.C++11简介 在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称.不过由于TC1主要是对C+ ...

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

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

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

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

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

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

  6. (原创)C++11改进我们的程序之右值引用

    http://www.cnblogs.com/qicosmos/p/3369940.html 本次主要讲c++11中的右值引用,后面还会讲到右值引用如何结合std::move优化我们的程序. c++1 ...

  7. C++11新特性——移动语义,右值引用

    移动语义 有一些类的资源是__不可共享__的,这种类型的对象可以被移动但不能被拷贝,如:IO 或 unique_ptr 库容器.string 和 shared_ptr 支持拷贝和移动,IO 和 uni ...

  8. (译)C++11中的Move语义和右值引用

    郑重声明:本文是笔者网上翻译原文,部分有做添加说明,所有权归原文作者! 地址:http://www.cprogramming.com/c++11/rvalue-references-and-move- ...

  9. C++ 11 左值,右值,左值引用,右值引用,std::move, std::foward

    这篇文章要介绍的内容和标题一致,关于C++ 11中的这几个特性网上介绍的文章很多,看了一些之后想把几个比较关键的点总结记录一下,文章比较长.给出了很多代码示例,都是编译运行测试过的,希望能用这些帮助理 ...

最新文章

  1. mysql密码高级_MySQL数据库高级操作(图文详解)
  2. java的语法树,JAVA语言语法树.doc
  3. oracle之单行函数之分组函数
  4. PrintArea打印,@media screen解决移动web开发的多分辨率问题,@media print设置打印的样式...
  5. [原创]部门年会活动流程
  6. linux配置apache服务器项目文档,Apache(Linux)服务器配置文档.doc
  7. 自动为数字千位数,百万位数添加逗号
  8. 机器学习面试-其他重要算法
  9. ICSharpCode.SharpZipLib实现压缩解压缩
  10. SnapHelper硬核讲解
  11. 如何免费的、完整的把 PDF 转换为 Word?
  12. 巴比特独家 | 我们梳理98家新三板公司年报,发现企业布局区块链6大特点
  13. matlab 仿真步长,matlab 仿真步长设置
  14. pix2pixHD:High-Resolution Image Synthesis and Semantic Manipulation with Conditional GANs
  15. flt 转word 图片不全(已解决)
  16. android 基础知识-LOG和版本解释
  17. 正则 验证密码(数字和英文同时存在)
  18. 批处理bat文件连接SQL Server数据库并执行相关sql代码
  19. robbin到此一游
  20. 一级减速器装配图和零件图——课程设计

热门文章

  1. 人工智能技术突破以及教育放量未来可期 增持评级
  2. 软件测试模型-瀑布模型
  3. xtile 下载_SMAPI出现问题有没有大佬帮忙解决一下
  4. DeepFaceLab: A simple, flexible and extensible face swapping framework 一个简单、灵活和可扩展的人脸交换框架
  5. 被动抓病毒的日子(2)【入侵大佬:xia.beihaixue.com】 直接跑满在下的CPU (*‘へ‘*)
  6. 【一起入门MachineLearning】中科院机器学习-期末题库-【计算题14+多选题10】
  7. php获取页面视频文件,PHP获取各大视频网站页面中的Flash播放地址
  8. 【html】网页缩小,页面的元素不会改变位置
  9. 【酒店管理系统】(二)表设计
  10. jdbc连接阿里云mysql相关问题