【C++】深入理解decltype和decltype(auto)

news2025/1/17 15:51:13

深入理解decltype和decltype(auto)

  • 一、decltype语法介绍
  • 二、decltype的推导规则
    • 1. expr不加括号
    • 2. expr加上括号
  • 三、关于decltype的CV属性推导
  • 四、 decltype(auto) 的使用

一、decltype语法介绍

decltype关键字是C++11新标准引入的关键字,它和关键字auto的功能类似,也可以自动推导出给定表达式的类型,但它和auto的语法有些不同,auto推导的表达式放在=的右边,并作为auto所定义的变量的初始值,而decltype是和表达式结合在一起,语法如下:

decltype(expr) var;

它的语法像是函数调用,但它不是函数调用而是运算符,和sizeof运算符类似,在编译期间获取他的类型,表达式expr不会被真正执行,因此不会产生汇编代码。

decltypeauto在功能上大部分相似,但推导规则和应用场景存在一些区别:

  • auto定义变量时必须提供初始值表达式,利用初始值表达式推导出类型并用它作为变量的初始值,使用auto作为值语义的推导时,会忽略表达式expr的引用性CV属性
  • decltype定义变量时可以不需要初始值。还有decltype可以保留引用性CV属性
  • 引用性:表达式的引用属性,如左值引用或者右值引用。
  • CV 属性:指的是 const 和 volatile 修饰符。它们用于修饰类型,以指定对象的特殊属性和行为。

二、decltype的推导规则

decltype的推导规则主要有三条规则:

  • 如果 expr 一个类成员访问表达式,或者是一个单独的变量,decltype(expr) 的类型就和 expr 一致,这是最普遍最常见的情况。
  • 如果 expr 是函数调用,那么 decltype(expr) 的类型就和函数返回值的类型一致。
  • 如果 expr 是一个左值,或者被括号()包围,那么 decltype(expr) 的类型就是 expr 的引用;假设 expr 的类型为 T,么 decltype(expr) 的类型就是 T&

为了更好地理解 decltype 的推导规则,下面来看几个实际的例子。

1. expr不加括号

#include <iostream>
#include <type_traits>

int func(int x) {
	return x;
}

class Base {
public:
	int x = 0;
};


int main()
{
	// 情况1
	int i = 1;
	const int& j = i;

	decltype(j) x = j;	
	decltype(i) y = i;

	// is_same是C++11之后的一个类模板,用于判断两个类型是否一致
	cout << "x is const int& ? " << std::boolalpha << std::is_same<decltype(x), const int&>::value << endl;
	cout << "y is int ? " << std::boolalpha <<std::is_same<decltype(y), int>::value << endl;

	const Base b;
	cout << "decltype(b.x) is int ? " << std::boolalpha << std::is_same<decltype(b.x), int>::value << endl;

	int  x1 = 1, x2 = 2;
	cout << "decltype(x1 + x2) is int ? " << std::boolalpha << std::is_same<decltype(x1 + x2), int>::value << endl;
	cout << "decltype(x1, x2) is int ? " << std::boolalpha <<std::is_same<decltype(x1, x2), int>::value << endl;
	cout << "decltype(x1, 0) is int ? " << std::boolalpha << std::is_same<decltype(x1, 0), int>::value << endl;

	// 情况2
	cout << "decltype(func(1)) is int ? " << std::boolalpha << std::is_same<decltype(func(1)), int>::value << endl;

	// 情况3
	int a[10] = { 0 };
	cout << "decltype(a[1] is int& ? " << std::boolalpha << std::is_same<decltype(a[1]), int&>::value << endl;

	return 0;
}

在这里插入图片描述

2. expr加上括号

int main()
{
	// 情况3
	int x1 = 1;
	int x2 = 2;
	const Base b;

	cout << "decltype((x1 + x2)) is int ? " << std::boolalpha << std::is_same<decltype((x1 + x2)), int>::value << endl;
	cout << "decltype((x1)) is int& ? " << std::boolalpha << std::is_same<decltype((x1)), int&>::value << endl;
	cout << "decltype((b.x)) is const int& ? " << std::boolalpha << std::is_same<decltype((b.x)), const int&>::value << endl;

	return 0;
}

在这里插入图片描述

(1)式中相加后的结果是一个右值,加上括号后依然是一个右值,因此推导结果是int

(2)式中跟之前没有加括号的情况不一样,加上括号相当于是返回x1变量,因此是一个左值,推导结果是一个引用。

(3)式返回的是一个左值,推导结果是一个引用,但因为定义的类对象b是一个const对象,要保持它的内容不可被修改,因此引用要加上const修饰。

三、关于decltype的CV属性推导

  • 通常情况下,decltype(expr)所推导的类型会同步expr的cv限定符
  • expr是未加括号的成员变量时,对象表达式的cv限定符会被忽略
class Base {
public:
	int x = 0;
};

int main()
{
	// CV限定符的推导
	const int i = 0;
	cout << "decltype(i) is const int ? " << std::boolalpha << std::is_same<decltype(i), const int>::value << endl;

	const Base b;
	cout << "decltype(b.x) is int ? " << std::boolalpha << std::is_same<decltype(b.x), int>::value << endl;
	cout << "decltype((b.x)) is const int& ? " << std::boolalpha << std::is_same<decltype((b.x)), const int&>::value << endl;
	return 0;
}

在这里插入图片描述

为什么decltype((b.x))const int&而不是const int呢?

因为decltype 的第三条推导规则:被括号()包围,会变成引用类型。

写到这里,不得不感概C++的语法是真的难,头都要给我学秃了…… 😭😭😭

四、 decltype(auto) 的使用

decltype(auto) 是 C++14 引入的一种类型推导机制,它结合了 decltypeauto 的特性。

使用 decltype(auto) 表示让auto使用自动类型推导,但推导的规则是按照decltype的规则来推导,这样在推导时会保留表达式的值的引用性和CV属性

decltype(auto)的使用语法规则如下:

decltype(auto) var = expr;
  • 简单使用示例:
int i = 1;
const int& j = i;
decltype(auto) x = j;	// x的类型为const int&
decltype(auto) y = i;	// y的类型为int
  • decltype(auto)用于推导函数返回值的类型
#include <iostream>
#include <vector>

std::vector<int> vec = {1, 2, 3, 4, 5};

// 返回左值引用
decltype(auto) getElementRef(size_t index) {
    return vec[index];
}

// 返回右值
decltype(auto) getElementValue(size_t index) {
    return vec[index] + 0;  // 使用右值表达式
}

int main() {
    // 使用 getElementRef 返回左值引用
    decltype(auto) ref = getElementRef(2);
    ref = 100;  // 修改引用的值
    std::cout << "vec[2]: " << vec[2] << std::endl;  // 输出 100

    // 使用 getElementValue 返回右值
    decltype(auto) val = getElementValue(2);
    std::cout << "val: " << val << std::endl;  // 输出 100

    return 0;
}
  • decltype(auto)使用陷阱

最后,对于decltype(auto)能够推导函数返回值为引用类型这一点,需要提醒一下的是,小心会有下面的陷阱,如下面的函数:

decltype(auto) func() {
    int x;
    // do something...
    return x;
}

这里推导出来的返回值类型是int,并且会拷贝局部变量x的值,这个没有问题。但如果是这样的定义:

decltype(auto) func() {
    int x;
    // do something...
    return (x);
}

这个版本返回的是一个引用,它将引用到一个即将销毁的局部变量上,当这个函数返回后,所返回的引用将引用到一个不存在的变量上,造成引用空悬的问题,程序的结果将是未知的。无论是有意的还是无意的返回一个引用,都要特别小心。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1804403.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

向量数据库是什么?

向量数据库是什么&#xff1f; 随着人工智能和机器学习技术的迅猛发展&#xff0c;向量数据库作为一种新型数据库引起了广泛关注。向量数据库专门用于存储和查询高维向量数据&#xff0c;是在大规模数据检索和相似性搜索领域的重要工具。 向量数据库的定义 向量数据库是一种…

心链13---主页切换功能 + loading特效 + 导航栏完善 + 队伍页接口修改

心链 — 伙伴匹配系统 直接取出所有用户&#xff0c;依次和当前用户计算分数&#xff0c;取 TOP N&#xff08;54 秒&#xff09; 优化方法&#xff1a; 切忌不要在数据量大的时候循环输出日志&#xff08;取消掉日志后 20 秒&#xff09;Map 存了所有的分数信息&#xff0c;占…

上位机图像处理和嵌入式模块部署(f407 mcu和其他mcu品类的选择)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 很多朋友读书的时候学的是stm32&#xff0c;工作中用的也是stm32。这本来问题不大&#xff0c;但是过去两三年的经历告诉我们&#xff0c;mcu的使用…

Polar Web【中等】反序列化

Polar Web【中等】反序列化 Contents Polar Web【中等】反序列化思路&探索EXPPHP生成PayloadGET传递参数 运行&总结 思路&探索 一个经典的反序列化问题&#xff0c;本文采用PHP代码辅助生成序列字符串的方式生成 Payload 来进行手动渗透。 打开站点&#xff0c;分析…

Python编程基础4

模块&#xff1a;模块支持从逻辑上组织Python代码&#xff0c;当代码量变得非常大的时候&#xff0c;最好把代码分成一些有组织的代码段。代码片段相互间有一定的联系&#xff0c;可能是一个包含数据成员和方法的类、函数、变量。 搜索路径&#xff1a;模块的导入需要一个叫做‘…

构建智能汽车新质生产力丨美格智能亮相2024高通汽车技术与合作峰会

近日&#xff0c;以“我们一起&#xff0c;驭风前行”为主题的2024高通汽车技术与合作峰会在无锡国际会议中心隆重举行。作为高通公司的战略合作伙伴&#xff0c;美格智能受邀全程参与此次汽车技术与合作峰会。在峰会现场&#xff0c;美格智能产品团队隆重展示了多款基于高通平…

Wireshark自定义Lua插件

背景&#xff1a; 常见的抓包工具有tcpdump和wireshark&#xff0c;二者可基于网卡进行抓包&#xff1a;tcpdump用于Linux环境抓包&#xff0c;而wireshark用于windows环境。抓包后需借助包分析工具对数据进行解析&#xff0c;将不可读的二进制数转换为可读的数据结构。 wires…

VUE封装-自定义权限控制指令

在实际开发中&#xff0c;会遇到很多的权限控制、资源位的场景&#xff0c;其实就是用来控制某个组件的展示与否&#xff0c;可以是一个按钮、一个报表、一个TAB页面等 例如下图&#xff0c;我想通过当前登录的用户控制谷歌的这个logo显示与否 因为设计到的权限、资源位控制比…

摆脱Jenkins - 使用google cloudbuild 部署 java service 到 compute engine VM

在之前 介绍 cloud build 的文章中 初探 Google 云原生的CICD - CloudBuild 已经介绍过&#xff0c; 用cloud build 去部署1个 spring boot service 到 cloud run 是很简单的&#xff0c; 因为部署cloud run 无非就是用gcloud 去部署1个 GAR 上的docker image 到cloud run 容…

GUI编程-01

组件 窗口 弹窗 面板 文本框 列表框 按钮 图片 监听事件 鼠标 键盘事件 破解工具 Java提供了丰富的图形用户界面&#xff08;Graphics User Interface&#xff0c;GUI&#xff09;的类库&#xff0c;基于这些类库可以编写窗口程序。 Java关于图形界面的类库主要放在…

【Redis学习笔记05】Jedis客户端(string、list、set)

Jedis客户端 1. 命令 1.1 String类型 1.1.1 常见命令 SET命令 语法&#xff1a;SET key value [EX seconds | PX milliseconds] [NX|XX] 说明&#xff1a;将string类型的value值设置到指定key中&#xff0c;如果之前该key存在&#xff0c;则会覆盖原先的值&#xff0c;原先…

数染色体 算法 python源码

效果图如下&#xff1a; 原图&#xff1a; 完整代码&#xff1a; import cv2 import numpy as np from skimage import measure import randomimage cv2.imread(113.jpg, cv2.IMREAD_GRAYSCALE)blurred_img cv2.GaussianBlur(image, (5, 5), 0)_, binary_image cv2.thresho…

LibreOffice电子表格如何实现快速筛选并将结果放到新的工作表

如果是在excel或者wps中&#xff0c;可能大家都习惯了自动筛选&#xff0c;然后复制到新的工作表或者删除掉复制内容的办法。但是在LibreOffice中&#xff0c;经测试&#xff0c;大数据表的删除或者复制是非常慢的。这也是很多人放弃LibreOffice的原因之一。那么我们如何快速筛…

Rust 实战丨SSE(Server-Sent Events)

&#x1f4cc; SSE&#xff08;Server-Sent Events&#xff09;是一种允许服务器向客户端浏览器推送信息的技术。它是 HTML5 的一部分&#xff0c;专门用于建立一个单向的从服务器到客户端的通信连接。SSE的使用场景非常广泛&#xff0c;包括实时消息推送、实时通知更新等。 S…

html+CSS+js部分基础运用18

1. 按键修饰符的应用。①姓名&#xff1a;按下回车键时调用方法输出“姓名-密码”&#xff1b;②密码&#xff1a;按下shift回车时调用方法输出“姓名密码” 图1 初始效果图 图2 按键修饰符效果图 2. 仿淘宝Tab栏切换&#xff0c;熟悉…

自动化您的Instagram帐户的程序InstaBot Pro 7.0.2

InstaBot Pro是一个自动化您的Instagram帐户的程序。InstaBot Pro允许您喜欢&#xff0c;搜索类似帐户上的新订阅者&#xff0c;并让真正的订阅者对您的内容感兴趣。InstaBot Pro还允许您向目标用户或帖子发送自动消息和评论。 InstaBot Pro具有简单方便的界面&#xff0c;您可…

CPU内部结构窥探·「3」

加法器的工作原理&#xff1a;从简单的逻辑到现代计算 我们在cpu内部结构窥探「1」中提到CPU内部ALU的核心部件就是运算器&#xff0c;今天就以加法器为例&#xff0c;来讲解我们ALU中算数逻辑运算的过程。 1.认识数字电路中的各种门电路 2. 什么是加法器&#xff1f; 加法器…

[Algorithm][动态规划][01背包问题][目标和][最后一块石头的重量Ⅱ]详细讲解

目录 1.目标和1.题目链接2.算法原理详解3.代码实现 2.最后一块石头的重量 II1.题目链接2.算法原理详解3.代码实现 1.目标和 1.题目链接 目标和 2.算法原理详解 问题转化&#xff1a;在数组中选择一些数&#xff0c;让这些数的和等于a&#xff0c;一共有多少种选法&#xff1f…

React实战(一)初始化项目、配置router、redux、axios

(一)初始化项目 1.安装项目 npx create-react-app 项目名 编译报错&#xff1a; 解决办法&#xff1a;安装最新的babel-preset-react-app npm install babel-preset-react-applatest 2.配置项目 (1)配置文件目录 (2)使用craco配置webpack.config npm install craco/crac…

HC05蓝牙模块与笔记本蓝牙连接

文章目录 1. 电脑和蓝牙模块连接 2. 串口软件调试 1. 电脑和蓝牙模块连接 HC05支持SPP协议&#xff0c;使用PC主机自带蓝牙&#xff0c;或者笔记本加蓝牙适配器。与HC05连接后&#xff0c;可在电脑端虚拟出串口&#xff0c;这样上位机软件就可以像操作串口一样与HC05通信。对…