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

C++(二)

C++11 类型分类

C++11 以后,进一步对类型进行了划分,右值被细分为纯右值 (prvalue)将亡值 (xvalue)

1. 纯右值 (pure value, 简称 prvalue)
  • 定义:指那些字面值常量,或求值结果相当于字面值,或是一个不具名的临时对象。
  • 等价关系:C++11 中的纯右值概念划分等价于 C++98 中的右值。
  • 常见示例
    • 字面值:42truenullptr
    • 不具名的临时对象或运算结果:str.substr(1, 2)str1 + str2
    • 传值返回的函数调用
    • 内置类型的运算:如整型aba++a + b
2. 将亡值 (expiring value, 简称 xvalue)
  • 定义:指返回右值引用的函数的调用表达式,以及转换为右值引用的转换函数的调用表达式。
  • 常见示例
    • std::move(x)
    • static_cast<X&&>(x)
3. 泛左值 (generalized lvalue, 简称 glvalue)
  • 定义:泛左值是一个更宽泛的概念,它包含了将亡值 (xvalue)和传统的左值 (lvalue)

C++ 引用折叠 (Reference Collapsing)

1. 基本概念与规则
  • 背景:C++ 中不能直接定义“引用的引用”,例如int& && r = i;会直接报错。但通过模板typedef中的类型操作可以间接构成引用的引用。
  • 折叠规则:当通过模板或 typedef 构成引用的引用时,C++11 给出了明确的折叠规则:
    • 右值引用的右值引用折叠成右值引用(&& &&->&&)。
    • 所有其他组合均折叠成左值引用(& &,& &&,&& &->&)。

2. typedef 与函数模板中的折叠演示

以下程序展示了在typedef和函数模板中,引用折叠的具体表现:

// 由于引用折叠限定,f1实例化以后总是一个左值引用template<classT>voidf1(T&x){}// 由于引用折叠限定,f2实例化后可以是左值引用,也可以是右值引用template<classT>voidf2(T&&x){}intmain(){typedefint&lref;typedefint&&rref;intn=0;// --- typedef 中的折叠规则 ---lref&r1=n;// r1 的类型是 int& (左值引用的左值引用 -> 左值引用)lref&&r2=n;// r2 的类型是 int& (左值引用的右值引用 -> 左值引用)rref&r3=n;// r3 的类型是 int& (右值引用的左值引用 -> 左值引用)rref&&r4=1;// r4 的类型是 int&& (右值引用的右值引用 -> 右值引用)// --- 模板 f1 的折叠演示 ---// 没有折叠 -> 实例化为 void f1(int& x)f1<int>(n);// f1<int>(0); // 报错,0为右值,无法传参// 折叠 -> 实例化为 void f1(int& x)f1<int&>(n);// f1<int&>(0); // 报错// 折叠 -> 实例化为 void f1(int& x)f1<int&&>(n);// f1<int&&>(0); // 报错// 折叠 -> 实例化为 void f1(const int& x)f1<constint&>(n);f1<constint&>(0);// const左值引用可以正常引用右值// 折叠 -> 实例化为 void f1(const int& x)f1<constint&&>(n);f1<constint&&>(0);// --- 模板 f2 的折叠演示 ---// 没有折叠 -> 实例化为 void f2(int&& x)// f2<int>(n); // 报错,右值引用不可以引用左值f2<int>(0);// 折叠 -> 实例化为 void f2(int& x)f2<int&>(n);// f2<int&>(0); // 报错,0为右值,无法传参// 折叠 -> 实例化为 void f2(int&& x)// f2<int&&>(n); // 报错f2<int&&>(0);return0;}

万能引用 (Universal Reference)

在像f2这样的函数模板中,T&& x参数看起来像是一个普通的右值引用参数,但由于引用折叠规则的存在,它的实际行为非常特殊:

  • 当传递左值时,它就是左值引用
  • 当传递右值时,它就是右值引用

因此,有些地方也把这种函数模板的参数叫做万能引用

推导原理

Function(T&& t)函数模板程序中,其背后的推导逻辑如下:

  1. 实参为右值时
    假设实参是int右值,模板参数T会被推导为int。结合引用折叠规则,最终实例化出右值引用版本的函数。
  2. 实参为左值时
    假设实参是int左值,模板参数T会被推导为int&。结合引用折叠规则(int& &&->int&),最终实例化出左值引用版本的函数。

完美转发 (Perfect Forwarding)

1. 为什么要使用完美转发?

Function(T&& t)函数模板程序中:

  • 传左值实例化以后是左值引用的Function函数。
  • 传右值实例化以后是右值引用的Function函数。

存在的问题
变量表达式都是左值属性。这意味着一个右值被右值引用绑定后,右值引用变量(即函数形参t)本身的属性是左值。如果我们直接把t传递给下一层函数Fun,那么匹配的永远都是左值引用版本的Fun函数。

为了在转发过程中保持t对象原始的左右值属性,我们需要使用完美转发。

2.std::forward的实现原理

std::forward本质是一个函数模板,主要通过引用折叠的方式实现。其核心源码简化如下:

template<class_Ty>_Ty&&forward(remove_reference_t<_Ty>&_Arg)noexcept{// 将参数无条件强转为 _Ty&&,利用引用折叠规则还原原始类型returnstatic_cast<_Ty&&>(_Arg);}
http://www.jsqmd.com/news/820219/

相关文章:

  • 2026年重庆除甲醛哪家口碑好?答案就在这里! - GrowthUME
  • 隐私保护新利器:VCamera虚拟摄像头工具使用全攻略
  • 全志V853双核开发实战:RISC-V E907小核启动与Linux-RTOS通信详解
  • Pydantic PyCharm插件:提升Python数据验证开发效率的智能IDE工具
  • Motrix官网下载与安装全攻略:免费开源的全能下载神器,小白也能轻松上手
  • 横向评测:东莞主流 AI 培训公司核心能力对比
  • BongoCat下载、安装和使用保姆级教程(附安装包,超详细)
  • Cadence Virtuoso IC617实战:手把手教你用gm/id方法搞定两级运放相位裕度(含密勒补偿避坑指南)
  • 奎屯装修公司靠谱选择 - GrowthUME
  • Wan Tasks API 集成与使用指南
  • 低成本组合导航系统:让精准导航不再昂贵
  • NetBeans集成ChatGPT插件开发:AI编程助手与经典IDE的融合实践
  • 日常常见轻微刮花,居家随手就能修
  • 2026年4月全国热门的铝加工设备定制怎么选,自动送料铝材切割机/全自动铝板锯/自动铝材切割机,铝加工设备设备找哪家 - 品牌推荐师
  • Python异步爬虫框架lightclaw:轻量级高性能Web数据采集实战
  • WasmEdge:高性能WebAssembly运行时在云原生与边缘计算中的应用
  • AI智能体技能学习:从算法原理到工程实践全解析
  • 影刀 RPA 给出的企业落地 RPA 项目的组织效率方案
  • ubuntu25 安装ORG flow
  • 开源AI智能体dreamGPT:让大语言模型学会自主思考与目标探索
  • 探索5大品牌水导激光器,揭秘哪家更值得信赖
  • 程序记忆系统设计:从向量检索到智能体上下文管理实战
  • 从零构建私有容器镜像仓库:基于Registry 2与MinIO的实战部署指南
  • WorkBuddy+PPT Master组合,AI-PPT 的效率革命
  • io_uring
  • 科技早报晚报|2026年5月14日:数据库沙箱、文档解析与 GPU 共享,今天更值得做成产品的 3 个技术机会
  • 《简明银行会计(程序员视角)》详细读书笔记
  • Trae IDE 实战:打造“创建完美智能体助手”(交互式+自动生成+模板删减,新手无脑上手)
  • WasmEdge:高性能WebAssembly运行时在云原生与边缘计算中的实践
  • 从时序到内存:51单片机驱动DHT11和OLED屏的5个常见坑点及解决方法