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

深入理解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);
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

html--酷炫背景引导主页

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>ZZVIPS酷炫背景引导主页</title><meta name"viewport" content"widthdevice-width,initial-scale1,maximum-scale1,user-scala…

社区贡献者分享 | OpenVINO™ 代码贡献助力我的开源之路

点击蓝字 关注我们,让开发变得更有趣 作者 | 占俊坚 排版 | 李擎 摘要 在 OpenVINO™ 2024.1 release 版本中&#xff0c;我为 OpenVINO™ 添加了 TensorFlow 中的 Rint operation 以及 PyTorch 中的 aten::bucketize operation 的支持&#xff0c;在此分享我的实现过程&#x…

最快的开源UDP传输工具:Kcptun

Kcptun&#xff1a;极速网络隧道&#xff0c;让数据传输飞起来&#xff01;- 精选真开源&#xff0c;释放新价值。 概览 kcptun 是一个轻量级、高性能的TCP/UDP网络加速工具&#xff0c;由xtaci开发并托管在GitHub上。它通过使用kcp协议&#xff0c;为网络数据传输提供了一个快…

深度解析:AI Prompt 提示词工程的兴起、争议与未来发展

PART1: 提示词工程的兴起 在人工智能领域中&#xff0c;一个新的领域——提示词工程&#xff08;prompt engineering&#xff09;——开始显露头角。 这个领域的核心在于精心设计输入&#xff0c;以引导AI模型产生特定的、期望的输出。 随着AI技术的飞速发展&#xff0c;特别…

移除重复节点---链表

面试题 02.01. 移除重复节点 - 力扣&#xff08;LeetCode&#xff09; 链表指针p和curr 与head指向同一块空间&#xff1b; p和head来比较相同的值&#xff0c;遇到一样的值、就改变这个空间里面struct的成员变量next指针指向的地址&#xff0c;跳向next的next再比较&#xf…

深度网络学习笔记(二)——Transformer架构详解(包括多头自注意力机制)

Transformer架构详解 前言Transformer的整体架构多头注意力机制&#xff08;Multi-Head Attention&#xff09;具体步骤1. 步骤12. 步骤23. 步骤34. 步骤4 Self-Attention应用与比较Self-Attention用于图像处理Self-Attention vs. CNNSelf-Attention vs. RNN Transformer架构详…

Kimichat使用案例010:快速识别出图片中的表格保存到Excel

文章目录 一、介绍二、图片信息三、输入内容四、输出内容五、markdown提示词六、markdown输出一、介绍 如果有一张图片格式的表格,想要快速复制到Excel表格中,那么一般要借助于OCR工具。之前试过不少在线OCR工具,识别效果差强人意。其实,kimichat就可以非常好的完成这个任务…

为什么需要在微服务中使用链路追踪?Spring Cloud 可以选择哪些微服务链路追踪方案?

引言&#xff1a;在当今的软件开发领域中&#xff0c;微服务架构已经成为了构建大型应用程序的主流方式之一。随着微服务数量的增加和服务之间复杂性的提高&#xff0c;对于了解和监控服务之间的调用关系变得越来越重要。而链路追踪技术的出现&#xff0c;为解决这一难题提供了…

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

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

[ROS 系列学习教程] 建模与仿真 - 使用 Arbotix 控制机器人

ROS 系列学习教程(总目录) 本文目录 一、Arbotix 简介二、安装Arbotix三、配置Arbotix控制器四、配置launch启动文件五、数据交互接口六、在rviz中仿真控制机器人6.1 直接发topic控制6.2 使用键盘控制6.3 编写代码控制机器人移动 前面讲了机器人的建模&#xff0c;是静态的&…

力扣 240.搜素矩阵II

题目描述&#xff1a; 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,4,7,11,15],[2,5,8,12,19],[3,6,9…

Kali Linux 2024.2 释出

渗透测试发行版 Kali Linux 释出了最新的 2024.2。 主要新特性包括&#xff1a;桌面环境更新到 GNOME 46&#xff0c;Xfce 环境加入 HiDPI 模式&#xff0c;更新了网络侦察工具 AutoRecon&#xff0c;监视 Linux 进程的命令行工具 pspy&#xff0c;提取和显示 CVE 信息的 Splo…

Oxlint 会取代 Eslint 吗?

最近&#xff0c;一个基于 Rust 的代码检查工具 Oxlint 在国外前端社区引起了热议&#xff0c;许多专家对其给予了高度评价。那么&#xff0c;相比于它的大哥 Eslint&#xff0c;Oxlint 有哪些优势&#xff1f;它会在未来取代 Eslint 吗&#xff1f;本文将讨论这个话题。 Oxc 和…

XUbuntu22.04之ssh+x11显示远程图形到本机(二百四十四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

[羊城杯 2023]CSGO

主函数初始化时&#xff0c;有反调试检测 打个断点在前面&#xff0c;然后nop掉 go语言的主函数是main_main 直接来到main_main&#xff0c;发现能可能是base64变表 在前面打个断点&#xff0c;F9 此处为base64变表&#xff0c;来到v25的地址处 得到变表LMNOPQRSTUVWXYZab…

[大模型]CharacterGLM-6B Transformers部署调用

环境准备 在autodl平台中租一个3090等24G显存的显卡机器&#xff0c;如下图所示镜像选择PyTorch–>2.0.0–>3.8(ubuntu20.04)–>11.8 接下来打开刚刚租用服务器的JupyterLab&#xff0c;并且打开其中的终端开始环境配置、模型下载和运行demo。 pip换源和安装依赖包 …

PyQt5 多进程 多任务 多线程实现进度条功能 无边框 含源码

概述&#xff1a; 在项目 中我们常遇到&#xff0c;大量计算或者加载数据时&#xff0c;需要用到多线程&#xff0c;此时只能等待&#xff0c;我们这个时间需要添加一下进度条&#xff0c;告诉用户当前需要等待&#xff0c;这时间就需要用到多线程和等待进度条&#xff1b; 效…

SpringCloudAlibaba基础二 Nacos注册中心

一 什么是 Nacos 官方&#xff1a;一个更易于构建云原生应用的动态服务发现(Nacos Discovery )、服务配置(Nacos Config)和服务管理平台。 集 注册中心配置中心服务管理 平台。 Nacos 的关键特性包括: 服务发现和服务健康监测动态配置服务动态 DNS 服务服务及其元数据管理 …

【教程】让小爱音箱Play增强版接入Mi-GPT

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 项目地址&#xff1a;https://github.com/idootop/mi-gpt MiIOT&#xff1a;小米小爱音箱Play 增强版 - 产品规格 - Xiaomi Miot Spec 实现效果图&…

Eslint配置指南

1. Eslint配置指南 1.1. 安装 ESLint1.2. 生成配置文件1.3. 修改配置文件1.4. 创建 .eslintignore 文件1.5. 运行 ESLint1.6. 整合到编辑器/IDE1.7. 自动修复 2. 配置prettier 2.1. 安装依赖包2.2. .prettierrc.json添加规则2.3. .prettierignore忽略文件2.4. 保存自动格式化 3…