当前位置: 首页 > news >正文

条款24:区分通用引用和右值引用

1 通用引用和右值引用

  1. T&& 既可以表示右值引用,也可以表示通用引用。
    1)右值引用仅绑定到右值,主要用于识别可以移动的对象。
    2)通用引用在源代码中看起来像右值引用,但行为可以类似于左值引用,并且可以绑定到各种类型的对象,包括const、volatile修饰的对象。
void f(Widget&& param); 	   // 右值引用
Widget&& var1 = Widget(); 	   // 右值引用
auto&& var2 = var1; 		   // 不是右值引用
template<typename T>
void f(std::vector<T>&& param); // 右值引用 
template<typename T>
void f(T&& param); 		   // 不是右值引用
  1. 通用引用出现的两种情况:第一个,也是最最常见的,是用于函数模板参数:
template<typename T> void f(T&& param); 	// param 是一个通用引用

第二个是auto声明:

auto&& var2 = var1; 	      // var2 是一个通用引用

这两种情况的共同点是存在类型推导

  1. 与此相比,如果看到没有类型推导的T&&,那么就是右值引用:
void f(Widget&& param);     // 没有类型推导;  param 是一个右值引用
Widget&& var1 = Widget();   // 没有类型推导;  var1 是一个右值引用
  1. 通用引用是引用,必须进行初始化。
  2. 如果初始化值是右值,则通用引用对应右值引用;如果初始化值是左值,则通用引用对应左值引用。例如,在函数模板f中,param是一个通用引用。如果将左值w传递给f,则param的类型是Widget&(即左值引用)。如果将std::move(w)传递给f,则param的类型是Widget&&(即右值引用)。
template<typename T>
void f(T&& param);  // param 是通用引用
Widget w;
f(w);               // 左值传给 f; param 的类型是 Widget& 
f(std::move(w));    // 右值传给 f; param 的类型是 Widget&& 
  1. 要使引用成为通用的,类型推导是必要的,但这还不够。引用声明的形式必须只能是:T&&。
template<typename T>
void f(std::vector<T>&& param); // param 是一个右值引用

当调用 f 时,类型 T 将被推导。但是 param 的类型声明形式不是T&&,而是std::vector&&。因此,param 是一个右值引用,如果尝试将一个左值传递给 f:

std::vector<int> v;
f(v); // 错误!不能将左值绑定到右值引用
  1. 即使存在一个简单的 const 限定符也足以使引用失去通用性:
template<typename T>
void f(const T&& param); // param 是一个右值引用
  1. 即使在模板中看到一个函数参数的类型是T&&,也不能假设它是通用引用,因为在模板中并不一定存在类型推导。考虑一下 std::vector 中的 push_back 成员函数:
template<class T, class Allocator = allocator<T>> // 来自 C++  标准
class vector { 
public:
//push_back 不能没有特定的vector实例化而存在,而该实例化的类型完全决定了 push_back 的声明void push_back(T&& x);...
};
std::vector<Widget> v; // 会导致 std::vector 模板如下实例化:
class vector<Widget, allocator<Widget>> {
public:
void push_back(Widget&& x); // 右值引用
...
};

push_back 没有使用类型推导。std::vector 中概念上类似的 emplace_back 成员函数确实采用了类型推导:

template<class T, class Allocator = allocator<T>> // 仍然来自C++标准
class vector {  
public:  
//在这里,类型参数 Args 与 vector 的类型参数 T 是独立的,因此 Args 必须在每次调用 emplace_back 时进行推导template <class... Args>void emplace_back(Args&&... args);...
};
  1. 通用引用的形式必须是T&&。没有要求使用名称 T。例如,下面的模板采用通用引用,因为形式(type&&)是正确的,并且 param 的类型将被推导(排除调用者明确指定类型的边角情况):
template<typename MyTemplateType> // param 是一个通用引用
void someFunc(MyTemplateType&& param);  
  1. 使用类型 auto&& 声明的变量是通用引用,因为类型推导会发生,并且它们具有正确的形式(T&&)。auto 通用引用在 C++14 中出现的频率要比在C++11中高得多,因为 C++14 中的 lambda 表达式可以声明 auto&& 参数。例如,如果想编写一个 C++14 lambda 来记录任意函数调用所花费的时间:
 auto timeFuncInvocation =
[](auto&& func, auto&&... params) {// C++14start timer;std::forward<decltype(func)>(func)( // 使用params调用funcstd::forward<decltype(params)>(params)...  );//停止计时器并记录运行时间;
};

1)func 是一个通用引用,可以绑定到任何可调用的对象、左值或右值。
2)args 是通用引用参数包,可以绑定到任意数量的任意类型的对象。
3)timeFuncInvocation 几乎可以对于任何函数的执行进行计时。

2 要点速记

  1. 如果函数模板参数的类型为 T&&,并用于推导类型 T,或者如果使用 auto&&声明对象,则该参数或对象是通用引用 。
  2. 如果类型声明的形式不是精确的 type&&,或者如果没有发生类型推导,则 type&&表示右值引用。
  3. 如果通用引用用右值初始化,则得到右值引用。如果用左值初始化,则得到左值引用。
http://www.dtcms.com/a/536146.html

相关文章:

  • zookeeper + kafka
  • 旅游网站建设与规划网站可以做被告嘛
  • 医护上门系统开发的关键技术解析与实践指南
  • 大模型-模型压缩:量化、剪枝、蒸馏、二值化 (3
  • Win10结束支持后,Linux发行版ZorinOS下载量两天破10w?怎么安装?
  • php和mysql做租车网站平台广告投放
  • Spring Boot3零基础教程,KafkaTemplate 发送消息,笔记77
  • 强化学习2.3 MDP价值迭代和策略迭代收敛证明
  • 网站建设公司相关资质重养网站建设
  • Android 中 RecyclerView 控件实现局部刷新而非整行刷新
  • STM32学习路线!软硬件兼修:裸机+RTOS+LVGL+硬件设计+项目实战 (STM32多核心开发板)
  • iOS 26 文件导出与数据分析,多工具组合下的开发者实践指南
  • Gradle 与 CI/CD 集成:Jenkins/GitHub Actions 自动化构建配置
  • STM32——IWDG
  • 一般的网站开发语言用什么免费网页制作
  • 浅述视频汇聚平台EasyCVR视频编解码与转码技术如何成就视频体验
  • 站长工具seo域名解析不了腾讯微信小程序公众号
  • cms网站访问人数网站主机多大
  • 基于线性预测算法的PON系统动态资源调度matlab仿真
  • 10月27日
  • 系规案例模拟题分享
  • flink实验三:实时数据流处理(踩坑记录)
  • Milvus简介
  • 高并发内存池 - 开发记录08,09
  • 廊坊网站排名优化公司哪家好哈尔滨网站制作公司
  • Node.js 数据查询优化技巧
  • 最新电子电气架构(EEA)调研-2
  • 【数据结构】顺序表+回调函数
  • 图像归一化:OpenCV 高效映射 [0,255] → [-1,1] 性能实测
  • allWebPlugin.IE扩展使用介绍