C++ 的 decltype 详细介绍

2023-11-03

1. 基本介绍

decltype 是 C++11 新增的一个用来推导表达式类型的关键字。和 auto 的功能一样,用来在 编译时期 进行自动类型推导。引入 decltype 是因为 auto 并不适用于所有的自动类型推导场景,在某些特殊情况下 auto 用起来很不方便,甚至压根无法使用。也可以将 decltype 看作是 sizeof 运算符的另一种形式,因为两者都不会真正计算其参数,只充当一种编译期工具的角色。

auto varName = value;
decltype(exp) varName = value;
  • auto 根据 = 右边的初始值推导出变量的类型,decltype 根据 exp 表达式推导出变量的类型,跟 = 右边的 value 没有关系;
  • auto 要求变量必须初始化,因为 auto 是根据变量的初始值来推导变量类型的,如果不初始化,变量的类型也就无法推导;
  • decltype 不要求,因此可以写成如下形式:
decltype(exp) varName;

原则上讲,exp 只是一个普通的表达式,它可以是任意复杂的形式,但必须保证 exp 的结果是有类型的,不能是 void;如果 exp 为一个返回值为 void 的函数时,exp 的结果也是 void 类型,此时会导致编译错误。

2. decltype 的几种形式

int x = 0;
decltype(x) y = 1;            // y -> int
decltype(x + y) z = 0;        // z -> int
const int& i = x;
decltype(i) j = y;            // j -> const int&
const decltype(z) *p = &z;    // *p -> const int, p -> const int*
decltype(z) *m = &z;          // *m -> int, m -> int*
decltype(m)* n = &m;          // *n -> int*, n -> int**

3. 推导规则

decltype 的推导规则可以简单概述如下:

  1. 如果 exp 是一个不被括号()包围的表达式,或者是一个类成员访问表达式,或者是一个单独的变量,decltype(exp) 的类型和 exp 一致。

代码示例:

#include<string> 
#include<iostream>
using namespace std;
 
class A {
public:
    static int total;
    string name;
    int age;
    float scores;
}
 
int A::total = 0;
 
int main()
{
	int n = 0;
	const int &r = n;
	A a;
	decltype(n) x = n;           // n 为 int,x 被推导为 int
	decltype(r) y = n;           // r 为 const int &,y 被推导为 const int &
	decltype(A::total)  z = 0;   // total 是类 A 的一个 int 类型的成员变量,z 被推导为 int
	decltype(A.name) url = "www.baidu.com"; // url 为 string 类型
	
	return 0;
}
  1. 如果 exp 是函数调用,则 decltype(exp) 的类型就和函数返回值的类型一致。

代码示例:

int& func1(int, char);   // 函数返回值为 int&
int&& func2(void);       // 函数返回值为 int&&
int func3(double);       // 函数返回值为 int
 
const int& func4(int, int, int);  // 函数返回值为 const int&
const int&& func5(void);          // 函数返回值为 const int&&
 
int n = 50;
decltype(func1(100,'A')) a = n; // a 的类型为 int&
decltype(func2()) b = 0;        // b 的类型为 int&&
decltype(func3(10.5)) c = 0;    // c 的类型为 int
 
decltype(func4(1,2,3)) x = n;    // x 的类型为 const int&
decltype(func5()) y = 0;         // y 的类型为 const int&&

exp 中调用函数时需要带上括号和参数,但这仅仅是形式,并不会真的去执行函数代码。

  1. 如果 exp 是一个左值,或被括号()包围,decltype(exp) 的类型就是 exp 的引用,假设 exp 的类型为 T,则 decltype(exp) 的类型为 T&

代码示例:

class A 
{
public:
   int x;
}
 
int main()
{
	const A obj;
	decltype(obj.x) a = 0;   // a 的类型为 int
	decltype((obj.x)) b = a; // b 的类型为 int&
	 
	int n = 0, m = 0;
	decltype(m + n) c = 0;     // n + m 得到一个右值,c 的类型为 int
	decltype(n = n + m) d = c; // n = n + m 得到一个左值,d 的类型为 int &
	return 0;
}

左值:表达式执行结束后依然存在的数据,即持久性数据;右值是指那些在表达式执行结束不再存在的数据,即临时性数据。一个区分的简单方法是:对表达式取地址,如果编译器不报错就是左值,否则为右值。

  1. 类的静态成员可以使用 auto, 对于类的非静态成员无法使用 auto,如果想推导类的非静态成员的类型,只能使用 decltype

代码示例:

template<typename T>
class A
{
private :
   decltype(T.begin()) m_it;
   // typename T::iterator m_it;   // 这种用法会出错
public:
	void func(T& container)
	{
	   m_it = container.begin();
	}
};
 
int main()
{
	const vector<int> v;
	A<const vector<int>> obj;
	obj.func(v);
	return 0;
}

4. 其它

此外,可以在函数模板、类模板和 lambda 表达式中使用 decltype,从而推断类型或者声明类型。

下面给出的示例代码展示了如何在 lambda 表达式中使用 decltype

#include <iostream>

int main()
{
    int x = 42;
    auto f = [&](decltype(x)& val) { val += 1; };
    f(x);

    std::cout << "x: " << x << std::endl;  // x: 43

    return 0;
}

在这个例子中,定义了一个 lambda 表达式 f,它的参数使用了 decltype 推断出参数类型为 int&。由于在 lambda 表达式中使用的变量必须是可见的,因此在 lambda 表达式前面的捕获列表中使用了 [&],以让 lambda 表达式捕获 x。最后,调用 lambda 表达式 f,并将变量 x 作为参数传递给它,从而使 x 的值被加 1。

参考该博文

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

C++ 的 decltype 详细介绍 的相关文章

  • 将复选框添加到 UniformGrid

    我正在尝试将复选框动态添加到 wpf 中的统一网格中 但看起来网格没有为它们分配足够的空间 所以它们都有点互相重叠 这就是我将它们添加到后面的代码中的方法 foreach string folder in subfolders PathCh
  • 检查两个数是否是彼此的排列?

    给定两个数字 a b 使得 1 例如 123 是 312 的有效排列 我也不想对数字中的数字进行排序 如果您指的是数字的字符 例如 1927 和 9721 则 至少 有几种方法 如果允许排序 一种方法是简单地sprintf将它们放入两个缓冲
  • 无法使用已与其底层 RCW 分离的 COM 对象。在 oledb 中

    我收到此错误 但我不知道我做错了什么 下面的代码在backrgroundworker中 将异常详细信息复制到剪贴板 System Runtime InteropServices InvalidComObjectException 未处理 通
  • 访问私人成员[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 通过将类的私有成员转换为 void 指针 然后转换为结构来访问类的私有成员是否合适 我认为我无权修改包含我需要访问的数据成员的类 如果不道德 我
  • 是否可以强制 XMLWriter 将元素写入单引号中?

    这是我的代码 var ptFirstName tboxFirstName Text writer WriteAttributeString first ptFirstName 请注意 即使我使用 ptFirstName 也会以双引号结束 p
  • C# 和 Javascript SHA256 哈希的代码示例

    我有一个在服务器端运行的 C 算法 它对 Base64 编码的字符串进行哈希处理 byte salt Convert FromBase64String serverSalt Step 1 SHA256Managed sha256 new S
  • 如何使用GDB修改内存内容?

    我知道我们可以使用几个命令来访问和读取内存 例如 print p x 但是如何更改任何特定位置的内存内容 在 GDB 中调试时 最简单的是设置程序变量 参见GDB 分配 http sourceware org gdb current onl
  • C++ 子字符串返回错误结果

    我有这个字符串 std string date 20121020 我正在做 std cout lt lt Date lt lt date lt lt n std cout lt lt Year lt lt date substr 0 4 l
  • Newtonsoft JSON PreserveReferences处理自定义等于用法

    我目前在使用 Newtonsoft Json 时遇到一些问题 我想要的很简单 将要序列化的对象与所有属性和子属性进行比较以确保相等 我现在尝试创建自己的 EqualityComparer 但它仅与父对象的属性进行比较 另外 我尝试编写自己的
  • 当 contains() 工作正常时,xpath 函数ends-with() 工作时出现问题

    我正在尝试获取具有以特定 id 结尾的属性的标签 like span 我想获取 id 以 国家 地区 结尾的跨度我尝试以下xpath span ends with id Country 但我得到以下异常 需要命名空间管理器或 XsltCon
  • 为什么#pragma optimize("", off)

    我正在审查一个 C MFC 项目 在某些文件的开头有这样一行 pragma optimize off 我知道这会关闭所有以下功能的优化 但这样做的动机通常是什么 我专门使用它来在一组特定代码中获得更好的调试信息 并在优化的情况下编译应用程序
  • 获取没有非标准端口的原始 url (C#)

    第一个问题 环境 MVC C AppHarbor Problem 我正在调用 openid 提供商 并根据域生成绝对回调 url 在我的本地机器上 如果我点击的话 效果很好http localhost 12345 login Request
  • Web API - 访问 DbContext 类中的 HttpContext

    在我的 C Web API 应用程序中 我添加了CreatedDate and CreatedBy所有表中的列 现在 每当在任何表中添加新记录时 我想填充这些列 为此目的我已经覆盖SaveChanges and SaveChangesAsy
  • 如何将图像路径保存到Live Tile的WP8本地文件夹

    我正在更新我的 Windows Phone 应用程序以使用新的 WP8 文件存储 API 本地文件夹 而不是 WP7 API 隔离存储文件 旧的工作方法 这是我如何成功地将图像保存到 共享 ShellContent文件夹使用隔离存储文件方法
  • Qt表格小部件,删除行的按钮

    我有一个 QTableWidget 对于所有行 我将一列的 setCellWidget 设置为按钮 我想将此按钮连接到删除该行的函数 我尝试了这段代码 它不起作用 因为如果我只是单击按钮 我不会将当前行设置为按钮的行 ui gt table
  • 从库中捕获主线程 SynchronizationContext 或 Dispatcher

    我有一个 C 库 希望能够将工作发送 发布到 主 ui 线程 如果存在 该库可供以下人员使用 一个winforms应用程序 本机应用程序 带 UI 控制台应用程序 没有 UI 在库中 我想在初始化期间捕获一些东西 Synchronizati
  • 如何使我的表单标题栏遵循 Windows 深色主题?

    我已经下载了Windows 10更新包括黑暗主题 文件资源管理器等都是深色主题 但是当我创建自己的 C 表单应用程序时 标题栏是亮白色的 如何使我自己的桌面应用程序遵循我在 Windows 中设置的深色主题 你需要调用DwmSetWindo
  • 将文本叠加在图像背景上并转换为 PDF

    使用 NET 我想以编程方式创建一个 PDF 它仅包含一个背景图像 其上有两个具有不同字体和位置的标签 我已阅读过有关现有 PDF 库的信息 但不知道 如果适用 哪一个对于如此简单的任务来说最简单 有人愿意指导我吗 P D 我不想使用生成的
  • mysql-connector-c++ - “get_driver_instance”不是“sql::mysql”的成员

    我是 C 的初学者 我认为学习的唯一方法就是接触一些代码 我正在尝试构建一个连接到 mysql 数据库的程序 我在 Linux 上使用 g 没有想法 我运行 make 这是我的错误 hello cpp 38 error get driver
  • C 中的异或运算符

    在进行按位操作时 我在确定何时使用 XOR 运算符时遇到一些困难 按位与和或非常简单 当您想要屏蔽位时 请使用按位 AND 常见用例是 IP 寻址和子网掩码 当您想要打开位时 请使用包含或 然而 XOR 总是让我明白 我觉得如果在面试中被问

随机推荐

  • python自动化笔记(四)列表

    my list 定义一个空列表 my list1 a b c my list2 list abc mylist1和mylist2效果一致 i 0 while i lt len my list1 循环输出list print my list1
  • yolov5加入分割头,多任务头

    Yolov5同时进行目标检测和分割分割 MidasKing的博客 CSDN博客 yolov5分割 用YOLOv5ds训练自己的数据集 注意点 用猪头过日子 的博客 CSDN博客 基于pytorch用yolov5算法实现目标检测与分割 无损检
  • js数学对象(Math)

    Math ceil 12 3 13 返回的是大于该数字的最小整数 Math floor 12 7 12 返回的是小于该数的最大整数 Math round 12 6 13 将数字进行四舍五入 Math max 12 30 15 100 求最大
  • 【设计模式】单例模式(懒汉和饿汉模式详解)

    目录 1 设计模式是什么 2 单例模式 1 概念 2 如何设计一个单例 1 口头约定 不靠谱 2 使用编程语言的特性来处理 3 使用 饿汉模式 设计单例 1 详细步骤 2 完整代码 4 使用 饿汉模式 设计单例 1 详细步骤 2 完整代码
  • mongodb持久化原理

    mongodb与mysql不同 mysql的每一次更新操作都会直接写入硬盘 但是mongo不会 做为内存型数据库 数据操作会先写入内存 然后再会持久化到硬盘中去 那么mongo是如何持久化的呢 mongodb在启动时 专门初始化一个线程不断
  • Spring概念:容器、Ioc、DI

    目录 什么是容器 什么是 IoC 传统程序的开发 理解 Spring IoC DI 总结 我们通常所说的 Spring 指的是 Spring Framework Spring 框架 它是 个开源框架 有着活跃 庞 的社区 这就是它之所以能
  • 前端知识点总结(一):从输入URL到页面展示的详细过程

    这里只是简单地概括一下大致流程 输入网址 DNS解析 建立tcp连接 客户端发送HTPP请求 服务器处理请求 服务器响应请求 浏览器展示HTML 浏览器发送请求获取其他在HTML中的资源 1 输入地址 当我们开始在浏览器中输入网址的时候 浏
  • 在页面中输入上下居中点号(·)

    随便打开一个聊天窗口输入汉字 点 在弹出的选项框中选择 号即可
  • dz安装好后css js位置错误,Discuz!X3.2安装后无法加载CSS/Js文件

    今天在服务器上安装了Discuz X3 2 数据库等填写正确 下一步很快就新建了291张表完成安装 没有任何报错出现 完成后访问前台和后台却无法加载CSS Js文件 F12查看它直接访问的网站根目录下边 这CSS Js文件明明不在根目录啊
  • AcWing 1293. 夏洛克和他的女朋友 二分图

    题 是一个二分图染色 质数不是质数的质因子 因为质数不会有因子 所以质数全是颜色1 合数不是合数的质因子 因为合数不 质 所以合数全都是颜色2 n小于3的时候只有1种颜色 其他都是2种颜色 include
  • 计算机网络教程_复习整理第一章

    计算机网络教程 复习整理第一章 第一章 概述 第二章 物理层 第三章 数据链路层 文章目录 计算机网络教程 复习整理第一章 1 因特网 因特网的标准制定流程 2 电路交换 报文交换 分组交换 区分三者 3 计算机网络的性能指标 lt 速率
  • d3dcompiler_43.dll缺失怎么修复

    有网友在玩游戏时出现 无法启动程序 因为计算机中丢失d3dcompiler 43 dll 尝试重新安装该程序以解决问题 的提示 那么是什么原因造成丢失d3dcompiler 43 dll呢 缺少d3dcompiler 43 dll文件怎么办
  • GLUE数据集介绍:RTE、MRPC、SST-2、QNLI、MNLI、QQP

    自然语言处理 NLP 主要包括自然语言理解 NLU 和自然语言生成 NLG 为了让NLU任务发挥最大的作用 来自纽约大学 华盛顿大学等机构创建了一个多任务的自然语言理解基准和分析平台 也就是GLUE General Language Und
  • SpringBoot注解

    使用注解的优势 1 采用纯java代码 不在需要配置繁杂的xml文件 2 在配置中也可享受面向对象带来的好处 3 类型安全对重构可以提供良好的支持 4 减少复杂配置文件的同时亦能享受到springIoC容器提供的功能 一 注解详解 配备了完
  • HIve中的查询语句

    文章目录 Hive中的查询语句 1 基础语法 2 基本查询 Select From 2 1 数据准备 0 原始数据 1 创建部门表 2 创建员工表 3 导入数据 2 2 全表和特定列查询 1 全表查询 2 选择特定列查询 2 3 列别名 1
  • kafka相关操作命令

    kafka相关操作命令 原文链接 https blog csdn net wf3612581 article details 81842574 1 开启zookeeper集群 startzk sh 2 开启kafka集群 start kaf
  • 【修电脑】VMware 从GHO文件备份恢复Win10/Win7系统

    修电脑 VMware 从GHO文件备份恢复Win10 Win7系统 注意 参考 硬盘知识 一 硬盘接口的分类 二 硬盘的分类 按照硬盘材质分为两大类 按照接口类型区分 boot启动知识 Legacy BIOS引导 uefi引导启动流程 查看
  • 区块链关键机制分析

    区块链中三大关键机制 密码算法 1 Hash算法 2 非对称加密算法 3 数字签名 存储结构 共识机制 1 工作量证明 POW 2 权益证明 POS 3 股份授权证明 DPOS 4 实用拜占庭容错 PBFT 5 Raft算法 6 Rippl
  • ubuntu18.04升级cmake

    下载cmake cmake官网 https cmake org download sudo apt get install y build essential libssl dev wget https github com Kitware
  • C++ 的 decltype 详细介绍

    1 基本介绍 decltype 是 C 11 新增的一个用来推导表达式类型的关键字 和 auto 的功能一样 用来在 编译时期 进行自动类型推导 引入 decltype 是因为 auto 并不适用于所有的自动类型推导场景 在某些特殊情况下