《Effective Modern C++》学习笔记 - Item 24: 区分万能引用和右值引用

本文详细介绍了C++中的万能引用(Universal References)和右值引用的概念,强调了它们在模板函数参数和auto变量推导中的应用。通过示例解释了如何区分万能引用和右值引用,并指出类型推导在判断引用类型中的关键作用。同时,指出了万能引用实际是右值引用和左值引用的抽象,并预告了引用折叠这一底层原理将在后续内容中探讨。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • T&&两种含义:
  1. 右值引用,只能绑定到右值上。
  2. 万能引用(作者称为 “universal references” ),可以绑定到任何类型的变量上,包括左值或右值,const 或 non-const,volatile 或 non-volatile,以及以上的任何组合。
  • 万能引用出现在两个情景中:
  1. 模板函数的参数, 形式为:

    template<typename T>
    void f(T&& param); // param is a universal reference
    
  2. auto 变量推导,形式为:

    auto&& var2 = var1; // var2 is a universal reference
    
  • 万能出现的必要条件是存在类型推导。如果看到了不存在类型推导的 T&&,那么就是右值引用,例如:
void f(Widget&& param); 	// no type deduction;
 							// param is an rvalue reference
Widget&& var1 = Widget(); 	// no type deduction;
 							// var1 is an rvalue reference
  • 除了存在类型推导,万能引用还要求引用出现的形式必须为 T&&T 不能是任何复合类型或带修饰的类型。以下例子也为右值引用而非万能引用:
template<typename T>
void f(std::vector<T>&& param); 	// param is an rvalue reference

template<typename T>
void f(const T&& param); 			// param is an rvalue reference
  • 即使在模板函数中看到了 T&& 参数,也不能立刻敲定其为万能引用,因为在模板中不保证会存在类型推导。例如对于 STL 中的 std::vector
template<class T, class Allocator = allocator<T>> 	// from C++
class vector { 										// Standards
public:
 void push_back(T&& x);
};

push_back() 的参数虽然是 T&& 的形式,但这里没有类型推导,因为 push_back() 必须依赖于一个已经实例化的 vector 而存在,vector 实例化时就已经确定了 T 的类型。调用时,参数 T&& 已经确定为某个具体类型(如 int&&),是右值引用而非万能引用。相反,vector 的另一个成员函数 emplace_back 就会进行类型推导,其形式如下:

template<class T, class Allocator = allocator<T>> 	// still from
class vector { 										// C++ Standards
 template <class... Args>
 void emplace_back(Args&&... args);
};

注意这里的模板参数 Argsvector 的模板参数 T 无关。

  • auto 的情形显然符合以上条件:显然存在类型推导,并且形式正确(auto&&)。

  • 本 Item 的所有内容都是 “谎言”(高情商:是一种抽象),其底层的真相被称为 引用折叠(reference collapsing),在 Item 28 进行讨论。不过这种抽象对于正确理解源码(我看到的 T&& 只能绑定到右值还是任何对象?)很有帮助。(也有助于理解后面 Item 25 和 Item 26 的内容)

总结

  1. 如果一个模板函数的参数的形式为 T&&,且类型 T 涉及推导,或者一个对象是由 auto&& 声明,那个参数或对象就是万能引用。
  2. 如果类型声明的形式不恰好是 type&&,或者没有涉及类型推导,那么 type&& 就是一个右值引用。
  3. 万能引用由右值对象初始化时,就是右值引用;由左值对象初始化时,就是左值引用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值