引子

T&&在代码里并不总是右值引用:

void f(Widget&& param);      // rvalue reference

Widget&& var1 = Widget();      // rvalue reference

auto&& var2 = var1;        // not rvalue reference

template<typename T>
void f(std::vector<T>&& param); // rvalue reference template<typename T>
void f(T&& param); // not rvalue reference

T&&代表两种含义:

  • 右值引用
  • 万能引用(universal references, or forwarding references)

如何区分

万能引用一般出现在两个场景中:

  • 模板参数
template<typename T>
void f(T&& param); // param is a universal reference
  • auto声明
auto&& var2 = var1; // var2 is a universal reference

我们分别讨论下这两种场景。

模板参数

我们注意到,涉及到万能引用的地方,都会有参数推导的过程,例如上面的T和var2. 而右值引用则没有这个过程:

void f(Widget&& param);        // no type deduction; param is an rvalue reference

Widget&& var1 = Widget();     // no type deduction; var1 is an rvalue reference

但是即使语句设计到参数推导,也不一定就是万能引用。例如:

template<typename T>
void f(std::vector<T>&& param); // param is an rvalue reference std::vector<int> v;
f(v); // error! can't bind lvalue to rvalue reference

这点还是比较好理解的。万能引用需要依靠表达式来初始化自己是右值引用还是左值引用,但是上面这个例子没有表现出这一点,它仅仅是推断了T的类型,但是param的类型一直都是std::vector<T>&&

我们再举一个vector中的例子:

template<class T, class Allocator = allocator<T>>
class vector {
public: void push_back(T&& x); // rvalue reference template <class... Args>
void emplace_back(Args&&... args); // universal reference
};
  • push_back(T&& x)中的T&&为右值引用,因为这个虽然是T&&,但是不涉及到参数推导。当push_back被instantiated时,实际的调用类似于:
std::vector<Widget> v;

...
class vector<Widget, allocator<Widget>> {
public:
void push_back(Widget&& x); // rvalue reference

};

可以很明显的看出此时没有参数推导的过程。

  • template <class... Args> emplace_back(Args&&... args)中的Args&&为万能引用。Args与T是相互独立的,所以Args有一个独立的参数推断过程。

const disqualify universal reference

有意思的是,当参数加上const后,就一定是右值引用:

template <class T> int f(T&& heisenreference);
template <class T> int g(const T&&); int i;
int n1 = f(i); // calls f<int&>(int&)
int n2 = f(0); // calls f<int>(int&&)
int n3 = g(i); // error: would call g<int>(const int&&), which would bind an rvalue reference to an lvalue

至于为什么会有这个规定,按照Why adding const makes the universal reference as rvalue的说法,大体有两点原因:

  • const T&&允许你重载一个函数模板,它只接受右值引用。如果const T&&也被当做universal reference,那么将没有办法让函数只接受右值引用。
  • 显示禁用某个函数接受右值引用:template <typename T> void cref(const T&&) = delete;

auto声明

对于auto的场景来说,所有的auto&&都是万能引用,因为它总是有参数推导的过程。例如定义一个记录函数执行时间的lambda(C++14中允许使用auto来声明lambda的函数):

auto timeFuncInvocation = [](auto &&func, auto &&... params) {
start timer;
std::forward<decltype(func)>(func)( // invoke func
std::forward<decltype(params)>(params)... // on params
);
stop timer and record elapsed time;
};

(完)

朋友们可以关注下我的公众号,获得最及时的更新:

c++11-17 模板核心知识(十)—— 区分万能引用(universal references)和右值引用的更多相关文章

  1. c++11-17 模板核心知识(五)—— 理解模板参数推导规则

    Case 1 : ParamType是一个指针或者引用,但不是universal reference T& const T& T* Case 2 : ParamType是Univers ...

  2. [转载] C++11中的右值引用

    C++11中的右值引用 May 18, 2015 移动构造函数 C++98中的左值和右值 C++11右值引用和移动语义 强制移动语义std::move() 右值引用和右值的关系 完美转发 引用折叠推导 ...

  3. C++11中的右值引用

    原文出处:http://kuring.me/post/cpp11_right_reference May 18, 2015 移动构造函数 C++98中的左值和右值 C++11右值引用和移动语义 强制移 ...

  4. item 24: 区分右值引用和universal引用

    本文翻译自<effective modern C++>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 古人曾说事情的真相会让你觉得很自在,但是在适当的情 ...

  5. C++11左值引用和右值引用

    转载:https://www.cnblogs.com/golaxy/p/9212897.html C++11的左值引用与右值引用总结 概念 1.&与&&  对于在C++中,大家 ...

  6. C++11标准之右值引用(rvalue reference)

    1.右值引用引入的背景 临时对象的产生和拷贝所带来的效率折损,一直是C++所为人诟病的问题.但是C++标准允许编译器对于临时对象的产生具有完全的自由度,从而发展出了Copy Elision.RVO(包 ...

  7. 【C/C++开发】C++11:右值引用和转发型引用

    右值引用 为了解决移动语义及完美转发问题,C++11标准引入了右值引用(rvalue reference)这一重要的新概念.右值引用采用T&&这一语法形式,比传统的引用T&(如 ...

  8. [c++11]右值引用、移动语义和完美转发

    c++中引入了右值引用和移动语义,可以避免无谓的复制,提高程序性能.有点难理解,于是花时间整理一下自己的理解. 左值.右值 C++中所有的值都必然属于左值.右值二者之一.左值是指表达式结束后依然存在的 ...

  9. [转][c++11]我理解的右值引用、移动语义和完美转发

    c++中引入了右值引用和移动语义,可以避免无谓的复制,提高程序性能.有点难理解,于是花时间整理一下自己的理解. 左值.右值 C++中所有的值都必然属于左值.右值二者之一.左值是指表达式结束后依然存在的 ...

随机推荐

  1. while语句的一个使用技巧

    作用类似于可以输入一个不定量长度的数组,但是严格来说 不可能出现任意长度. 内存是有限的 超出一定长度后,不可能存的下,虽然这个值可能是超级大的,但总有限度. 这里我们利用while(cin>& ...

  2. pandas神器操作excel表格大全(数据分析数据预处理)

    使用pandas库操作excel,csv表格操作大全 关注公众号"轻松学编程"了解更多,文末有公众号二维码,可以扫码关注哦. 前言 准备三份csv表格做演示: 成绩表.csv su ...

  3. Jetbrains全系列产品 2020最新激活方法 (即时更新)

    即时更新:http://idea.itmatu.com/key Jetbrains全系列产品 2020最新激活方法 JMFL04QVQA-eyJsaWNlbnNlSWQiOiJKTUZMMDRRVlF ...

  4. Antisymmetry

    题意描述 Antisymmetry 求给定的字符串的子串集合中为"反对串"的个数. 反对串的定义为,将这个字符串 \(0\) 和 \(1\) 取反后,再将整个串反过来和原串一样,就 ...

  5. B/S图书管理系统

    B/S图书管理系统 系统管理 ①新用户注册 ②用户信息修改:修改信息,修改密码 ③锁定用户 ④注销用户 书籍管理 ①新书入库 ②借书办理 ③还书办理 ④书记注销 个人管理 ①图书查询 ②借书单查询 ③ ...

  6. java网络编程socket的使用

    Socket 客户端实例 如下的 GreetingClient 是一个客户端程序,该程序通过 socket 连接到服务器并发送一个请求,然后等待一个响应. GreetingClient.java 文件 ...

  7. 重构rbd镜像的元数据

    这个已经很久之前已经实践成功了,现在正好有时间就来写一写,目前并没有在其他地方有类似的分享,虽然我们自己的业务并没有涉及到云计算的场景,之前还是对rbd镜像这一块做了一些基本的了解,因为一直比较关注故 ...

  8. 文本多行省略号(CSS最优方案)

    Float定位溢出隐藏 优点: 纯CSS实现,性能好,不用js调优 兼容性高 多行省略,自动显示 缺点: 单词截断 代码如下: <div class="ellipses-div&quo ...

  9. 学习一下 Spring Security

    一.Spring Security 1.什么是 Spring Security? (1)基本认识 Spring Security 是基于 Spring 框架,用于解决 Web 应用安全性的 一种方案, ...

  10. Java8 方法引用和构造方法引用

    如果不熟悉Java8新特性的小伙伴,初次看到函数式接口写出的代码可能会是一种懵逼的状态,我是谁,我在哪,我可能学了假的Java,(・∀・(・∀・(・∀・*),但是语言都是在进步的,就好比面向对象的语言 ...