C++11 类型推导decltype(一)

2023-11-13

我们之前使用的typeid运算符来查询一个变量的类型,这种类型查询在运行时进行。RTTI机制为每一个类型产生一个type_info类型的数据,而typeid查询返回的变量相应type_info数据,通过name成员函数返回类型的名称。同时在C++11中typeid还提供了hash_code这个成员函数,用于返回类型的唯一哈希值。RTTI会导致运行时效率降低,且在泛型编程中,我们更需要的是编译时就要确定类型,RTTI并无法满足这样的要求。编译时类型推导的出现正是为了泛型编程,在非泛型编程中,我们的类型都是确定的,根本不需要再进行推导。
decltype与auto关键字一样,用于进行编译时类型推导。

与auto不同的是:decltype的类型推导并不是像auto一样是从变量声明的初始化表达式获得变量的类型,decltype总是以一个普通的表达式为参数,返回改表达式的类型。

与auto相同的是:作为一个类型指示符,decltype可以将获得的类型来定义另外一个变量。

decltype的应用

1.推导出表达式类型

int i = 4;
decltype(i) a;     //推导结果为int,a的类型为int

2.与using/typedef合用,用于定义类型,提高代码可读性

using size_t = decltype(sizeof(0));    //sizeof(a)的返回值为size_t类型
using ptrdiff_t = decltype((int*)0 - (int*)0);
using nullptr_t = decltype(nullptr);

vector<int >vec;
typedef decltype(vec.begin()) vectype;
for (vectype i = vec.begin; i != vec.end(); i++)
{
    //...
}

3.重用匿名类型

#include <iostream>

enum {
    K1 = 0,
    K2 = 1,
}anon_e;

union {
    decltype(anon_e) k;
    char *name;
}anon_u;

struct {
    int d;
    decltype(anon_u) id;
}anon_s;

int main()
{
    decltype(anon_s) as;        //定义了一个上面匿名的结构体
    as.id.k = decltype(anon_e)::K1;
    std::cout << as.id.k << std::endl;
    return 0;
}

而借助decltype,我们可以重新使用匿名结构体:

4.泛型编程中结合auto,用于追踪函数的返回值类型

(decltype最大的用途之一就是用于追踪返回类型的函数中)

template <typename _Tx, typename _Ty>
auto multiply(_Tx x, _Ty y)->decltype(_Tx*_Ty)
{
    return x*y;
}

decltype推导四规则

(1).如果e是一个没有带括号的标记符表达式或者类成员访问表达式,那么的decltype(e)就是e所命名的实体的类型。此外,如果e是一个被重载的函数,则会导致编译错误。

(2).否则 ,假设e的类型是T,如果e是一个将亡值,那么decltype(e)为T&&

(3).否则,假设e的类型是T,如果e是一个左值,那么decltype(e)为T&。

(4).否则,假设e的类型是T,则decltype(e)为T。

标记符指的是除去关键字、字面量等编译器需要使用的标记之外的程序员自己定义的标记,而单个标记符对应的表达式即为标记符表达式。

int arr[4];    //arr为一个标记符表达式,而arr[3]+0不是。

我们来看下面这段代码:

int i=10;
decltype(i) a;     //a推导为int
decltype((i))b=i;  //b推导为int&,必须为其初始化,否则编译错误  

仅仅为i加上了(),就导致类型推导结果的差异。这是因为,i是一个标记符表达式,根据推导规则1,类型被推导为int。而(i)为一个左值表达式(有具体名字的地址),所以类型被推导为int&。

通过下面这段代码可以对推导四个规则作进一步了解:

int i = 4;
int arr[5] = { 0 };
int *ptr = arr;
struct S{ double d; }s ;
void Overloaded(int);
void Overloaded(char);  //重载的函数
int && RvalRef();
const bool Func(int);

//规则一:推导为其类型
decltype (arr) var1;      //int 标记符表达式
decltype (ptr) var2;      //int *  标记符表达式
decltype(s.d) var3;       //doubel 成员访问表达式

//decltype(Overloaded) var4;    //重载函数。编译错误。

//规则二:将亡值。推导为类型的右值引用。
decltype (RvalRef()) var5 = 1;

//规则三:左值,推导为类型的引用。
decltype ((i))var6 = i;           //int&
decltype (true ? i : i) var7 = i; //int&  条件表达式返回左值。
decltype (++i) var8 = i;          //int&  ++i返回i的左值。
decltype(arr[5]) var9 = i;        //int&. []操作返回左值
decltype(*ptr)var10 = i;          //int& *操作返回左值
decltype("hello")var11 = "hello"; //const char(&)[9]  字符串字面常量为左值,且为const左值。


//规则四:以上都不是,则推导为本类型
decltype(1) var12;                //const int
decltype(Func(1)) var13=true;     //const bool
decltype(i++) var14 = i;          //int i++返回右值    

这里需要提示的是,字符串字面值常量是个左值,且是const左值,而非字符串字面值常量则是个右值。
这么多规则,对于我们写代码的来说难免太难记了,特别是规则三。我们可以利用C++11标准库中添加的模板类is_lvalue_reference来判断表达式是否为左值:

std::cout << std::is_lvalue_reference<decltype(++i)>::value << std::endl;

结果1表示为左值,结果为0为非右值。
同样的,也有is_rvalue_reference这样的模板类来判断decltype推断结果是否为右值。

限制符的继承

auto类型推导时不能带走CV限制符,decltype能够带走表达式的CV限制符。不过如果对象的定义中有const或volatile限制符,使用decltype进行推导时,对象中的成员不会继承const或volatile限制符。

#include <iostream>
#include <type_traits>

int main()
{
    const int ic = 0;
    volatile int iv;
    struct S{ int i; };

    const S a = {0};
    volatile S b;
    volatile S*p = &b;
    std::cout << std::is_const<decltype(ic)>::value << std::endl;       //1 推导类型为:const int
    std::cout << std::is_volatile<decltype(iv)>::value << std::endl;    //1 推导类型为:volatile int

    std::cout << std::is_const<decltype(a)>::value << std::endl;        //1 推导类型为:const S
    std::cout << std::is_volatile<decltype(b)>::value << std::endl;     //1 推导类型为:volatile S

    std::cout << std::is_const<decltype(a.i)>::value << std::endl;      //0 推导类型a为const,但是成员不继承const类型
    std::cout << std::is_volatile<decltype(p->i)>::value << std::endl;  //0 推导类型p为volatile,但是成员不继承volatile类型

    return 0;
}

限制符的冗余

与auto相同的是:decltype从表达式推导出类型后,进行类型定义时,也会运行一些冗余符号,比如CV限制符以及引用符&。通常情况下,如果推导出的类型已经有了这些属性,冗余的符号则会被忽略。与auto声明中,也可以是冗余的不同,decltype后的号,并不会被编译器忽略。

#include <iostream>
#include <type_traits>

int main()
{
    int i = 1;
    int& j = i;
    int *p = &i;
    const int k = 1;

    decltype(i)& var1 = i;
    decltype(j)& var2 = i;
    std::cout << std::is_lvalue_reference<decltype(var1)>::value << std::endl;    //1,时左值引用
    std::cout << std::is_rvalue_reference<decltype(var2)>::value << std::endl;    //0,不是右值引用
    std::cout << std::is_lvalue_reference<decltype(var2)>::value << std::endl;    //1,是左值引用

    //decltype(p)* var3 = &i;   //编译错误
    decltype(p)* var4 = &p;     //var4的类型为int **

    auto* v3 = p;               //v3的类型为int *
    v3 = & i;
    const decltype(k) var5 = 1; //冗余的const,被忽略

    return 0;
}

转自:https://www.cnblogs.com/DswCnblog/p/6537411.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++11 类型推导decltype(一) 的相关文章

  • 计算机的性能指标完全由cpu决定是否正确,计算机的性能指标完全由CPU决定对吗...

    电脑性能由CPU 中央处理器 主板 显卡 网卡 声卡等共同决定 如果主板 显卡不行 CPU再好也不行 这5个中 CPU 主板 显卡在决定电脑性能中占的比重大一些 推荐学习 phpstorm 1 运算速度 计算机运算速度是指每秒钟所能执行的指
  • 记录Windows10中Docker安装Mysql5.7

    DockerHub 搜索Mysql找到官方镜像 官方镜像地址 拉取mysql5 7版本镜像 拉取 docker pull mysql 5 7 查看docker 镜像 就能看到拉取的镜像 docker images 运行一个mysql容器 创
  • 电脑开机check_码住!常见电脑蓝屏代码和解决方法

    电脑蓝屏是很多人都碰到过的突发情况 引起电脑蓝屏的原因有很多 在软件方面 可能是因为个别软件或者驱动导致的 也可能是电脑中了病毒或者操作系统损坏等原因 硬件方面 可能是因为电脑散热不良 内存损坏 内存条接触不良或者电脑超频过度 硬盘坏道等问
  • anaconda换源和恢复默认源

    1 查看当前环境下的源 conda config show sources 2 换清华源 conda config add channels https mirrors tuna tsinghua edu cn anaconda pkgs
  • Android插件化主流框架和实现原理

    写在前面 这几年移动开发业界兴起的 插件化技术 的旋风 各个大厂都推出了自己的插件化框架 各种开源框架都评价自身功能优越性 令人目不暇接 随着公司业务快速发展 项目增多 开发资源却有限 如何能在有限资源内满足需求和项目的增长 同时又能快速响
  • (CentOS 7) PostgreSQL安装与配置

    一 安装相关配置软件 root www1 yum install y gcc x86 64 glibc x86 64 glibc devel x86 64 vim enhanced x86 64 gcc java apr apr devel
  • parted扩展磁盘分区(实践篇)

    系统环境 操作系统 centos7 2 前言 突然发现根下的空间不足了 没有找到可以释放的磁盘空间 所以决定要扩展一下磁盘分区 直接上操作 环境分析 发现根下的磁盘空间已经不是很充足了 看图片 显示的sda2的空间只给了280G 已经快要占
  • cgroup----devices子系统

    devices子系统 使用devices 子系统可以允许或者拒绝cgroup中的进程访问设备 devices子系统有三个控制文件 devices allow devices deny devices list devices allow用于
  • 下级对上级回复收悉_领导发微信“辛苦啦”怎么回复?学会这几点,让你被高看一眼...

    有网友说 在职场 领导晚上发微信交代任务 完成后发结果给他 领导回了句辛苦 如何巧妙回应他 有时候 简单的问题就不要特别复杂化 就像这个话题所言 领导给你发微信交代任务 你做完了后交差 领导回复句辛苦 我想这句话并没有特别深的含义 可能是领
  • 偏微分方程基础

    第五十篇 偏微分方程 一个偏微分方程 PDE 包含两个或多个自变量的导数 这与之前描述的常微分方程 ODE 相反 后者只涉及一个自变量 工程和科学中的许多现象都是用偏微分方程描述的 例如 一个因变量 如压力或温度 可以作为时间 t 和空间
  • 页面刷新后DataGrid重新定位

    VB NET Private Sub scroll ByVal index As Integer Dim s As String s Page RegisterStartupScript s End Sub C private void S
  • Qt中查看ui_xxx.h文件方法

    前提 1 Qt当有界面 2 构造完成 满足以上两个条件qt会生成ui xxx h文件 如何查看 方法1 在cpp文件中找到UI下的一个对象 如 ui gt textEdit Ui QWDialog 按住Ctrl键 使用鼠标左键点击UI下的一
  • Mybatis_lazyLoadingEnabled延迟加载配置

    via https item congci com content mybatis lazyloadingenabled yanchi jiazai peizhi 一 什么是延迟加载 resultMap可以实现高级映射 使用associat
  • vue 水印组件

    vue2 水印效果 效果图展示 Watermark 参数 说明 类型 默认值 width 水印的宽度 content 的默认值为自身的宽度 number 120 height 水印的高度 content 的默认值为自身的高度 number
  • 【Hello Algorithm】最大线段重合及加强堆

    本篇博客简介 介绍加强堆 加强堆 最大线段重合问题 加强堆 计算时间复杂度的技巧 一般来说 我们在刷算法的时候都要求C C 语言在1到2s之内完成 java这种语言在2到4秒之内完成 而与之对应的指令条数就是 十的八次方 左右 不会超过一个
  • android 刷机后熄屏断网

    情况说明 我的黑鲨1代刷机后 部署了Linux系统 但是只要熄屏后过一会儿就无法访问网络了 尝试了修改电量管理 关闭省电模式等 均无效 经过很久很久的测试 终于找到了原因 Android6 0或更高版本系统有一个Doze模式和App Sta
  • centos虚拟机服务器手把手搭建

    虚拟机服务对于开发人员来说 并不陌生 熟悉项目环境搭建 服务部署 运维集成 前期准备 1 下载一个VMware Workstation 工具 链接 https pan baidu com s 1lh68j846lxMfKVGtUlMNXA
  • Android 使用motion 动画如何使用

    MotionLayout 是 Android 中的一个强大的布局容器 它可以用来创建复杂的动画和过渡效果 允许你在布局中定义多个状态 并在这些状态之间进行平滑的动画过渡 以下是使用 MotionLayout 创建动画的基本步骤 1 添加依赖
  • 演化博弈论基本概念

    文章目录 混合策略 符号 混合策略的空间几何 策略组合的表示 混合策略收益函数 最优反应 最佳反应集合 混合策略 符号 标准博弈可以写成 G I S

随机推荐

  • 智慧园区参观纪要

    首都国企开放日期间 云梯联盟举办了 深入走进创新主体 活动 昨天参观了牡丹集团旗下的智慧园区 现在做一个简单的纪要 1 国企战略转型经历的四个阶段 第一个阶段是初创时期实施 一体化 战略 发展园区服务业 第二个阶段是起步时期实施 一体两翼
  • USART与UART的区别

    USART universal synchronous asynchronous receiver and transmitte 通用同步异步收发器 USART是一个串行通信设备 可以灵活地与外部设备进行全双工数据交换 UART unive
  • apt-get install 错误解决

    E Could not get lock var lib dpkg lock open 11 Resource XXX unavailable E Unable to lock the XXX directory var lib dpkg
  • 如何删除git submodules

    Stage the gitmodules changes git add gitmodules Delete the relevant section from git config Remove the submodule files f
  • shell 清理日志文件内容

    一般日志文件都是 按照yyyy MM dd 格式划分的文件 bin bash function read dir ls date date Y m d for file in ls 1 do if d 1 file then read di
  • HBase-10 Region的分裂策略

    Region的分裂策略 1 region 分裂策略 ConstantSizeRegionSplitPolicy IncreasingToUpperBoundRegionSplitPolicy SteppingSplitPolicy KeyP
  • delphi怎么通过企业微信自建应用接收用户发送的信息

    如果你想在 Delphi 中使用企业微信自建应用接收用户发送的信息 你需要先了解企业微信自建应用的相关接口文档 然后 你可以使用 Delphi 的网络库 比如 Indy 或 Synapse 发送 HTTP 请求来调用这些接口 并解析响应内容
  • 小程序-吸顶下拉框

    今天给大家带来的是在开发小程序过程中遇到一个下拉菜单 废话不多说先给大家上一波图 感谢崔老师 其实是萌萌的大汉 给与后期帮助与完善 一开始页面硬画出来的效果还不错 但是需求做到后面发现又有多个下拉框菜单 但是菜单的内容同 熟悉下拉框的同学都
  • unity跳过QuickTime播放视频的另一种方式

    本文转载自http blog csdn net awnuxcvbn article details 17618919 点击这里下载视频转换器 该转换器会把其他格式转化为ogv格式 直接被unity识别 不需要安装quicktime不需要重启
  • GitHub命令汇总(实用版)

    问题 在GitHub使用过程中用命令git clone下载和使用页面上download zip的下载有什么不一样 使用git clone下载的是一个仓库 使用download zip下载的是一个普通文件夹 还需要用git init初始化才能
  • thinkPHP6.0入门笔记(六)——模板继承

    thinkPHP6 0的模板继承 1 构建简易导航栏 2 thinPHP6 0模板继承 1 构建简易导航栏 bootstrap提供了很多样式 但是怎么说 很多样式直接使用还是有点别扭 这里在PC端自定义一个导航栏 HTML代码如下
  • Centos7 使用yum从第三方仓库安装Python3.8

    环境 CentOS Linux release 7 9 2009 起因 Centos 7 自带Python2 7 5版本 而默认的 YUM 安装的python3是 3 6版本 遂升级到3 8版本 install Python3 8 yum
  • 解决若依后台管理系统打包线上偶发性elementUI的icon会出现乱码的问题

    1 问题图片 本地运行环境下是没有问题的 打包线上环境就会出现乱码情况 这时候我们发会发现在浏览器上看样式content 乱码 百度了很多 也尝试了各种方法都没有用 最后看到这篇博文添加链接描述得以解决 2 解决方法 升级sass版本至1
  • Vue中的生命周期

    什么是生命周期 生命周期 1 又名 生命周期回调函数 生命周期函数 生命周期钩子 2 是什么 Vue在关键时刻帮我们调用的一些特殊名称的函数 3 生命周期函数的名字不可更改 但函数的具体内容是程序员根据需求编写的 4 生命周期函数中的thi
  • Java的序列化

    写在前面 本文看下序列化和反序列化相关的内容 源码 1 为什么 什么是序列化和反序列化 Java对象是在jvm的堆中的 而堆其实就是一块内存 如果jvm重启数据将会丢失 当我们希望jvm重启也不要丢失某些对象 或者是需要将某些对象传递到其他
  • SQL8 查找某个年龄段的用户信息

    描述 题目 现在运营想要针对20岁及以上且23岁及以下的用户开展分析 请你取出满足条件的设备ID 性别 年龄 用户信息表 user profile id device id gender age university province 1
  • 前端UI组件库深度解析:构建现代化的用户体验

    引言 在当今的前端开发中 UI组件库已经成为了我们工具箱中不可或缺的一部分 这些库可以极大地提高我们的工作效率 同时也使我们能够专注于实现真正的业务逻辑 而不是重复地编写UI代码 本篇博客将详细地探讨UI组件库的核心概念 特性以及如何有效地
  • Stm32旧版库函数8——stm32 PWM波 TIM4 PB6 PB7 PB8 PB9

    include
  • html发布页,发布页入口.html

    发布页入口 axure utils getTransparentGifPath function return resources images transparent gif axure utils getOtherPath functi
  • C++11 类型推导decltype(一)

    我们之前使用的typeid运算符来查询一个变量的类型 这种类型查询在运行时进行 RTTI机制为每一个类型产生一个type info类型的数据 而typeid查询返回的变量相应type info数据 通过name成员函数返回类型的名称 同时在