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

C++11 新特性 decltype 说明符

一、typeof与typeid

1.1、typeof

在C++11标准之前,GCC已经提供了一个类似功能的运算符 typeof对类型进行推导,但是这毕竟是编译器的实现,不是标准。

int a = 0;
typeof(a) b = 5;

1.2、typeid

C++标准提供了 typeid 运算符,获取的类型信息会包含在一个类型为std::type_info的对象里,可以调用成员函数name获取其类型名。

int x1 = 0;
double x2 = 5.5;
std::cout << typeid(x1).name() << std::endl;
std::cout << typeid(x1 + x2).name() << std::endl;
std::cout << typeid(int).name() << std::endl;

成员函数name返回的类型名在C++标准中并没有明确的规范,所以输出的类型名会因编译器而异。

  • typeid的返回值是一个左值,生命周期直到当前函数周期结束

  • typeid返回的std::type_info删除了复制构造函数,若想保存std::type_info,只能获取其引用或者指针

    •   auto t1 = typeid(int);     // 编译失败,没有复制构造函数无法编译auto &t2 = typeid(int);    // 编译成功,t2推导为const std::type_info&auto t3 = &typeid(int);    // 编译成功,t3推导为const std::type_info*
      
  • typeid的返回值总是忽略类型的 cv 限定符,也就是typeid(const T) == typeid(T))

很明显,typeid有很大缺陷,它并不能像typeof那样在编译期就确定对象类型。

二、decltype

为了用统一方法解决上述问题,C++11标准引入了decltype说明符,使用decltype说明符可以获取对象或者表达式的类型,其语法与typeof类似:

int x1 = 0;
decltype(x1) x2 = 0;
std::cout << typeid(x2).name() << std::endl;  // x2的类型为intdouble x3 = 0;
decltype(x1 + x3) x4 = x1 + x3;
std::cout << typeid(x4).name() << std::endl;  // x1+x3的类型为doubledecltype({1, 2}) x5;                          // 编译失败,{1, 2}不是表达式

为了更好的讨论decltype的优势,需要用到返回类型后置。

auto sum(int a1, int a2)->int {return a1+a2;
}

上述代码中,以C++11为标准,auto作为占位符并不能使编译器对函数返回类型进行推导,必须使用返回类型后置的形式指定返回类型。如果想泛化这个函数,就需要用到函数模板

template<class R, class T1, class T2>
R sum(T1 a1, T2 a2) {return a1 + a2;
}auto x3 = sum<double>(5, 10.5);

满足泛化sum函数的要求,但必须为函数模板指定返回值类型。如何在编译期完成所有的类型推导工作?

template<class T1, class T2>
auto sum(T1 a1, T2 a2)->decltype(a1 + a2) {return a1 + a2;
}auto x4 = sum(5, 10.5);

decltype 完美地解决了之前需要指定返回类型的问题。在实例化sum函数的时候,编译器就能够知道sum的返回类型了。

C++14标准中,直接支持了对auto声明的返回类型进行推导

template<class T1, class T2>
auto sum(T1 a1, T2 a2) {return a1 + a2;
}

但是auto还存在一些小问题

template<class T>
auto return_ref(T& t) {return t;
}int x1 = 0;
static_assert(std::is_reference_v<decltype(return_ref(x1))>// 编译错误,返回值不为引用类型
);

上述代码中 auto 直接被推导为值类型(使用auto声明变量初始化时,目标对象如果是引用,则引用属性会被忽略),导致编译错误,

三、推导规则

decltype(e)(其中e的类型为T

1. 如果e是一个未加括号的标识符表达式(结构化绑定除外)或者未加括号的类成员访问,则decltype(e)推断出的类型是e的类型T。如果并不存在这样的类型,或者e是一组重载函数,则无法进行推导。

2.如果e是一个函数调用或者仿函数调用,那么decltype(e)推断出的类型是其返回值的类型。

3.如果e是一个类型为T的左值,则decltype(e)T&

4.如果e是一个类型为T的将亡值,则decltype(e)T&&

5.除去以上情况,则decltype(e)T

看几个例子

const int&& foo();
int i;
struct A {double x;
};
const A* a = new A();decltype(foo());         // decltype(foo())推导类型为const int&&    满足规则4
decltype(i);             // decltype(i)推导类型为int                满足规则1
decltype(a->x);          // decltype(a->x)推导类型为double          满足规则1
decltype((a->x));        // decltype((a->x))推导类型为const double& 满足规则3,加了括号就是表达式,表达式返回左值,还有const修饰,所以 (a->x) 的类型是 const double&,即指向 x 的常量引用。int i;
int *j;
int n[10];
decltype(i=0);                      // 推导类型为int&          表达式返回左值
decltype(0,i);                      // 推导类型为int&          逗号表达式,返回第二个值
decltype(i,0);                      // 推导类型为int          
decltype(n[5]);                     // 推导类型为int&          数组n中的第6个元素,左值
decltype(*j);                       // 推导类型为int&          左值
decltype(static_cast<int&&>(i));    // 推导类型为int&&         将亡值
decltype(i++);                      // 推导类型为int           右值
decltype(++i);                      // 推导类型为int&          左值
decltype("hello world");            // 推导类型为const char(&)[12] 常量数组左值

四、CV限定符

通常情况下,decltype(e)所推导的类型会同步ecv限定符,cv限定符这里是指onstvolatile关键字

const int i = 0;
decltype(i);         // 推导类型为const int

e是未加括号的成员变量时,父对象表达式的cv限定符会被忽略,不能同步到推导结果:

struct A {double x;
};
const A* a = new A();
decltype(a->x);     // 推导类型为double, const属性被忽略
decltype((a->x));   // 推导类型为const double&, const属性不被忽略

相关文章:

C++11 新特性 decltype 说明符

一、typeof与typeid 1.1、typeof 在C11标准之前&#xff0c;GCC已经提供了一个类似功能的运算符 typeof对类型进行推导&#xff0c;但是这毕竟是编译器的实现&#xff0c;不是标准。 int a 0; typeof(a) b 5;1.2、typeid C标准提供了 typeid 运算符&#xff0c;获取的类型…...

java线程局部变量使用方式

线程局部变量是Java中用于存储线程本地信息的变量。这种变量仅在线程的生命周期内存在&#xff0c;并且每个线程都有自己的一份拷贝。换句话说&#xff0c;线程局部变量是线程私有的&#xff0c;其他线程无法访问。 使用场景主要包括&#xff1a; 1. 存储线程状态信息&#xff…...

【隧道篇 / WAN优化】(7.4) ❀ 01. 启动WAN优化 ❀ FortiGate 防火墙

【简介】几乎所有的人都知道&#xff0c;防火墙自带的硬盘是用来保存日志&#xff0c;以方便在出现问题时能找到原因。但是很少的人知道&#xff0c;防火墙自带的硬盘其实还有另一个功能&#xff0c;那就是用于WAN优化。 防火墙自带的硬盘 在FortiGate防火墙A、B、C、D系列&…...

2024数维杯数学建模B题生物质和煤共热解问题的研究原创论文分享

大家好&#xff0c;从昨天肝到现在&#xff0c;终于完成了2024数维杯数学建模挑战赛B题的完整论文啦。 实在精力有限&#xff0c;具体的讲解大家可以去讲解视频&#xff1a; 2024数维杯数学建模B题煤共热解每一问高质量完整代码讲解&#xff01;_哔哩哔哩_bilibili 2024数维杯…...

中国电子学会(CEIT)2022年12月真题C语言软件编程等级考试三级(含详细解析答案)

中国电子学会(CEIT)考评中心历届真题(含解析答案) C语言软件编程等级考试一级 2022年12月 编程题五道 总分:100分一、鸡兔同笼(20分) 一个笼子里面关了鸡和兔子(鸡有2只脚,兔子有4只脚,没有例外)。已经知道了笼子里面脚的总数a,问笼子里面至少有多少只动物,至…...

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 5月12日,星期日

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年5月12日 星期日 农历四月初五 1、 全国多地已推“一次挂号管三天”&#xff0c;部分医院专家门诊适用。 2、 在梅大高速塌方事故中拦车、救援&#xff0c;黄曼秋等5人拟确认为见义勇为。 3、 深圳新能源车指标申请条件调…...

微服务思想以及实现

文章目录 前言一、什么时候需要拆分微服务1. 创业型项目2. 大型项目 二、怎么拆1. 拆分目标2. 拆分方式 三、微服务之间远程调用1. 实现方式2. 手动发送Http请求&#xff08;RestTemplate&#xff09;3. 服务注册中心3.1 原理3.2 Nacos注册中心3.3 服务注册3.4 服务发现(Discov…...

C语法:格式符号%f和%lf引发的错误

今天编程时有如下代码&#xff1a; #include"stdio.h"int main(void) {double profit;double bonus;printf("请输入本月利润\n");scanf("%f",&profit);//错误&#xff1a;此行profit是double类型&#xff0c;格式符为%f,当输入8时&#xff0…...

Java基础入门day48

day48 JDBC调用关系 tomcat 简介 tomcat是Apache下的一个核心项目&#xff0c;免费开源&#xff0c;支持servlet和jsp。 tomcat技术先进&#xff0c;性能稳定&#xff0c;目前比较流行的web应用服务器 安装 官网&#xff1a; Apache Tomcat - Welcome! 下载 tomcat8.5 解压&a…...

C++笔记(体系结构与内核分析)

1.OOP面向对象编程 vs. GP泛型编程 OOP将data和method放在一起&#xff0c;目的是通过封装、继承、多态提高软件的可维护性和可扩展性GP将data和method分开&#xff0c;可以将任何容器与任何算法结合使用&#xff0c;只要容器满足塞饭所需的迭代器类型 2.算法与仿函数的区别 …...

c++ 唤醒指定线程

在C中&#xff0c;直接唤醒一个特定的线程并不像在Java的Thread类中有interrupt()方法或者某些操作系统特定的API&#xff08;如POSIX的pthread_cond_signal或Windows的SetEvent&#xff09;那样简单。C标准库没有提供一个直接的方法来"唤醒"一个正在等待的线程。然而…...

java报错:使用mybatis plus查询一个只返回一条数据的sql,却报错返回了1000多条

今天遇到一个问题 系统线上问题&#xff0c;经常出现这样的问题&#xff0c;刚重启系统时不报错了&#xff0c;可是运行一段时间又会出现。sql已经写了limit 1&#xff0c;mybatis的debug日志也返回total为1&#xff0c;可是却报错返回了1805条数据 乍一看&#xff0c;感觉太不…...

AI图书推荐:利用生成式AI实现业务流程超自动化

《利用生成式AI实现业务流程超自动化》&#xff08;Hyperautomation with Generative AI&#xff09;这本书探索了广泛的用例和示例&#xff0c;展示了超自动化在不同行业、领域和特定部门的多样化应用&#xff0c; 让您熟悉UiPath、Automation Anywhere和IBM等流行工具和平台&…...

什么事防抖和节流,有什么区别,如何实现

防抖和节流&#xff0c;本质上是优化高频率执行代码的一种手段&#xff0c;比如&#xff1a;resize、scroll、keypress、mousemove这些事件在触发的时候&#xff0c;会不断调用绑定在事件上的回调函数&#xff0c;这样极大浪费资源&#xff0c;降低前端性能。 为了优化体验&am…...

PanguSync大数据量初始化脚本

由于数据库增量同步软件PanguSync初始化最大超时时间为600s,如果初始数据量很大&#xff0c;第一次部署时可能会超时&#xff0c;可以先停止任务&#xff0c;使用以下Sql语句进行初始化&#xff0c;以下语句可以分步执行&#xff0c;初始化完成后&#xff0c;后续无需再执行耗时…...

DELL T630服务器iDRAC分辨率调整办法

对于Dell T630服务器的iDRAC分辨率调整&#xff0c;您需要登录到iDRAC的Web界面。以下是详细的步骤&#xff1a; 登录iDRAC&#xff1a;在浏览器中输入iDRAC的IP地址&#xff0c;然后使用用户名&#xff08;通常是“root”&#xff09;和密码登录。 导航到虚拟控制台&#xff…...

您真的会高效使用 Mac 吗?

文章目录 屏幕的保养快捷键预览修改文件名查看文件属性搜索编辑复制&#xff0c;粘贴&#xff0c;剪切&#xff0c;撤销删除 跳转窗口屏幕截图声音Dock强制退出查字典神奇的Option键鼠标与触控板切换桌面与应用程序打开通知中心打开Mission Control 安装与卸载Mac应用程序压缩和…...

Vue11 Vue3完结撒花

shallowRef和shallowReactive shallowRef 作用&#xff1a;创建一个响应式数据&#xff0c;但只对顶层属性进行响应式处理 用法 let myVar shallowRef(initialValue)特点&#xff1a;只跟踪引用值变化&#xff0c;不关心值内部的属性变化 案例 <template><div c…...

CodeTop 高频笔试题总结(持续更新)

&#x1f3c6; 频率从高到低排序 &#x1f468;‍&#x1f3eb; 参考的频率数据&#xff1a;CodeTop &#x1f468;‍&#x1f3eb; 力扣hot100 无重复字符的最长子串 双指针 滑动窗口 哈希&#x1f468;‍&#x1f3eb; 力扣hot100 反转链表 指针 递归 一题多解&#x1f468;‍…...

类和对象一(从封装开始讲述)

目录&#xff1a; 一.封装 二.封装扩展之包&#xff0c;自定义包 三.访问限定符 四.static成员 一.封装&#xff1a;封装&#xff1a;将数据和操作数据的方法进行有机结合&#xff0c;隐藏对象的属性和实现细节&#xff0c;仅对外公开接口来和对象进行 交互。面向对象…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案

目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后&#xff0c;迭代器会失效&#xff0c;因为顺序迭代器在内存中是连续存储的&#xff0c;元素删除后&#xff0c;后续元素会前移。 但一些场景中&#xff0c;我们又需要在执行删除操作…...

Unity VR/MR开发-VR开发与传统3D开发的差异

视频讲解链接&#xff1a;【XR马斯维】VR/MR开发与传统3D开发的差异【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...

算术操作符与类型转换:从基础到精通

目录 前言&#xff1a;从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符&#xff1a;、-、*、/、% 赋值操作符&#xff1a;和复合赋值 单⽬操作符&#xff1a;、--、、- 前言&#xff1a;从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...