C++知识整理系列(三)—— constexpr常量表达式

2023-11-04

  • const修饰常量,但是const并未区分编译时常量和运行时常量,而constexpr则只能是编译时常量,在C++11中提出。
  • 这篇文章,将详细讲解constexpr。

一、常量表达式

常量表达式(const expression):指值不会改变并且在编译阶段过程就能得到计算结果的表达式。

以下两种是常量表达式:

const int maxSize = 10;
const int limit = maxSize + 1;

以下两种不是常量表达式:

int staff_size = 27;
const int sz = get_size();
  • staff_size的初始值虽然是个字面值常量,但它的数据类型只是普通的int而非const int,还是可以被重新赋值的,所以不是常量表达式。
  • sz本身是一个常量,但它的具体值直到运行时才能获取到,所以也不是常量表达式。

二、constexpr变量

在一个复杂系统中,很难分辨一个初始值到底是不是常量表达式。从前面的例子可以发现,即使变量加上const,但是赋值是在运行时确定的也不是常量表达式。

C++11新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。

  • 声明为constexpr的变量一定是一个常量。
  • 必须用常量表达式初始化。
constexpr int mf = 20;					//20是常量表达式
constexpr int limit = mf + 1;			//mf + 1是常量表达式
constexpr int sz = size();				//只有当size是一个constexpr函数时才是一条正确的声明语句

size()函数也需要constexpr修饰,成为constexpr函数。

三、constexpr函数

constexpr函数指能用于常量表达式的函数。定义constexpr函数有几项约定:

  • 函数的返回值类型及所有的类型都得是字面值类型
  • 函数体中必须有且只有一条return语句。
constexpr int new_sz() { return 40; }
constexpr int foo = new_sz();		//正确:foo是一个常量表达式

因为编译器能在程序编译时验证new_sz函数返回的是常量表达式,所以可以用new_sz函数初始化constexpr类型的变量foo。

(1)执行初始化任务时,编译器把对constexpr函数的调用替换成其结果值。为了能在编译过程中随时展开,constexpr函数被隐式地指定为内联函数

(2)constexpr函数体内也可以包含其他语句,只要这些语句在运行时不执行任何操作就行。例如,constexpr函数中可以有空语句、类型别名、using声明。

(3)constexpr函数的返回值可以不是一个常量

//cnt如果是常量表达式,返回值就是常量表达式
constexpr size_t scale(size_t cnt) { return new_sz() * cnt; }

比如,下面两个例子:

int arr[scale(2)];			//正确:scale(2)是常量表达式
int i = 3;
int a[scale(i)];			//错误:scale(i)不是常量表达式
  • 给scale传入字面值为2的常量表达式时,它的返回类型也是常量表达式。此时编译器用对应的结果值(80)替换为对scale函数的调用。
  • 当我们用一个非常量表达式调用scale函数时,比如int i = 3的对象i,返回值则不是一个常量表达式。当把scale函数用在需要常量表达式的上下文中时,编译器发现不是常量表达式,发出错误信息。

(4)constexpr函数通常定义在头文件中。因为编译器要想展开函数不仅需要函数声明还需要函数定义,而constexpr函数可以在程序中多次定义,但多个定义必须完全一致。

四、字面值类型

常量表达式的值需要在编译时就得到计算,因此对声明constexpr时用到的类型必须有所限制。因为这些类型一般比较简单,值也显而易见、容易得到,称之为"字面值类型"(literal type)。

字面值类型包括:算数类型、引用、指针,自定义类、string等类型不是字面值类型,也就不能定义成constexpr。

尽管指针和引用都能定义成constexpr,但它们的初始值却受到严格限制。一个constexpr指针的初始值必须是nullptr或者0,或者是存储在某个固定地址中的对象。

函数体内定义的变量一般来说并非存放在固定地址中,因此constexpr指针不能指向这样的变量。相反的,定义在函数体之外的对象地址固定不变,能用来初始化constexpr指针。

五、指针和constexpr

(1)如果在constexpr声明中定义了一个指针,限定符constexpr仅对指针有效,与指针所指的对象无关。

const int *p = nullptr;					//p是一个指向整数常量的指针
constexpr int *q = nullptr;				//q是一个指向整数的常量指针

q是一个常量指针,因为constexpr把它所定义的对象置为了顶层const。类似于:int *const q = nullptr;

(2)与其他常量指针类似,constexpr指针即可以指向常量也可以指向一个非常量:

constexpr int *np = nullptr;			//np是一个指向整数的常量指针,其值为空
int j = 0;
constexpr int i = 40;					//i的类型是整数常量
//假设i和j都定义在函数体之外
constexpr const int *p = &i;			//p是常量指针,指向整型常量i
constexpr int *p1 = &j;					//p1是常量指针,指向整数j

六、字面值常量类

constexpr函数的参数和返回值必须是字面值类型。注意,函数的返回值必须是字面值类型,但可以不是一个常量。

和其他类不同,字面值类型的类可能含有constexpr函数成员。这样的成员必须符合constexpr函数的所有要求,它们是隐式const。

字面值常量类:数据成员都是字面值类型的聚合类。如果一个类不是聚合类,但它符合下述要求,则它也是一个字面值常量类:

  • 数据成员都必须是字面值类型。
  • 类必须至少含有一个constexpr构造函数。
  • 如果一个数据成员含有类内初始值,这内置类型成员的初始值必须是一条常量表达式;如果成员属于某种类类型,这初始值必须使用成员自己的constexpr构造函数。
  • 类必须使用析构函数的默认定义,该成员负责销毁类的对象。

尽管构造函数不能是const的,但是字面值常量类的构造函数可以是constexpr函数。一个字面值常量类必须至少提供一个constexpr构造函数。

参考

  • C++ Primer


码字不易,觉得不错的小伙伴可以一键三连支持一下~
在这里插入图片描述

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

C++知识整理系列(三)—— constexpr常量表达式 的相关文章

随机推荐

  • 华硕计算机cpu怎么超频怎么设置,内存和CPU超频操作_华硕 ROG Rampage VI Apex_主板评测-中关村在线...

    进阶操作 进BIOS可能很多人都是为了去给CPU和内存进行超频 首先按F7进入到高级模式 华硕的主板选择Extreme Tweaker选项卡 有的主板是AI Tweaker或者超频设置等名字 Extreme Tweaker选项卡 内存超频
  • 如何使用postman做接口测试

    常用的接口测试工具主要有以下几种 Postman 简单方便的接口调试工具 便于分享和协作 具有接口调试 接口集管理 环境配置 参数化 断言 批量执行 录制接口 Mock Server 接口文档 接口监控等功能 JMeter 开源接口测试及压
  • Python中is和==(is not和!=)的区别

    Python中有很多种运算符 本文主要记录一下is和 这两种运算符的区别 id 函数是查看该对象所在内存地址 每个对象都有对应的内存地址 如 is 用于判断两个变量引用对象是否为同一个 用于判断引用变量的值是否相等 类似于Java中的equ
  • 华为OD机试 - 按单词下标区间翻转文章内容(Java)

    题目描述 给定一段英文文章片段 由若干单词组成 单词间以空格间隔 单词下标从0开始 请翻转片段中指定区间的单词顺序并返回翻转后的内容 例如给定的英文文章片段为 I am a developer 翻转区间为 0 3 则输出 developer
  • HJ26 字符串排序

    Powered by NEFU AB IN Link 文章目录 HJ26 字符串排序 题意 思路 代码 HJ26 字符串排序 题意 编写一个程序 将输入字符串中的字符按如下规则排序 规则 1 英文字母从 A 到 Z 排列 不区分大小写 如
  • PCL 计算点云法向量并显示

    目录 一 算法原理 1 法向量估计 2 法向量定向 3 表面曲率 4 参考文献 5 法向量定向的理解 6 CloudCompare 二 pcl Normal的定义 三 pcl Normal的几种输出方式 四 计算法线并显示 1 计算输入点云
  • 单点登录(简单的实现)

    假设现在有两个域名 分别为 分别记为client1 client2 client1 com client2 com 一个认证服务器 域名 ssoserver com client1 client2都需要登陆后才能访问到数据 现在想要实现cl
  • 76-C语言-输入班级学生的姓名和三科成绩,按总分排名

    问题 输入50分学生的姓名和三科成绩 按降序输出名字和总分 成绩相同的并列排名 思路 因为要学生排名 且一个学生有姓名 成绩 以及总分 所以弄一个学生的结构体 有多少学生 就输入该结构体的数组 一个for循环 给每个学生赋值 排序 降序 用
  • 【c++中的细节问题】关于typedef的详细用法

    请见 C C typedef用法详解 真的很详细 superhoy的专栏 CSDN博客 c typedef
  • 3.Linux文件管理和 I/O 重定向

    Linux文件管理和 I O 重定向 Linux文件系统目录结构 常见目录说明 根目录 一般根目录下只存放目录 在Linux下有且只有一个根目录 所有的东西都是从这里开始 当你在终端里输入 home 你其实是在告诉电脑 先从 根目录 开始
  • 利用多线程批Put方式压测HBase

    利用多线程批Put方式压测HBase 背景 在正式上生产之前 一定要对集群的组件做稳定性和性能压测 这是常识 这种压测当然不能指望那些只会鼠标点几下网页并经常指责前端页面样式有bug的测试去做 这种稍微有点技术含量的事情 她们其实有心无力
  • Mybatis中的#号与$符号的区别

    1 变量名 可以进行预编译 类型匹配等操作 2 变量名 会转化为jdbc的类型 3 变量名 不进行数据类型匹配 直接替换 4 方式能够很大程度防止sql注入 5 方式无法方式sql注入 6 方式一般用于传入数据库对象 例如传入表名 7 尽量
  • List取交集、并集、差集

    突然被面试官问到这样一个问题 List怎么取交集 我想了一会后说道双重循环 自己都觉得面试官想要的答案应该不是这个 效率太低了 后面问面试官答案 面试官告诉我可以将其中一个llist转成一个map或set 再遍历第二个list的时候判断 m
  • Vision Transformer

    A N I MAGE IS W ORTH 16 X 16 W ORDS TRANSFORMERS FOR I MAGE R ECOGNITION AT S CALE 原文链接地址 https arxiv org abs 2010 11929
  • shell学习:从ini文件中读取参数

    打算编写一个shell脚本来自动备份网站 需要从配置文件中读取一些参数 比如数据库名称 用户名和密码等 我分析了一下wdcp自带的数据库备份脚本mysqlbackup sh 里面仅仅从文件mrpw conf中读取了数据库密码 只用到了cat
  • 面试前需考虑的25个问题

    我曾经在The Simple Dollar上提到自己过去曾组织了大量面试工作 虽然我招聘的通常是技术类职位 但实际问到的问题 因此是有实际价值的 都是无关技术的 一个好的面试问题能使应聘者的本性显露出来 诚实 可信 反应敏锐等等 长期以来
  • vue项目嵌入iframe后访问后端报错

    项目场景 最近的项目中 开发的项目中需要使用到另外的一个即时通讯im项目 当时使用ifram标签进行嵌入 跳转失败 问题描述 在使用ifram进行嵌入后 刷新页面 ifram的地址会直接覆盖掉父类地址进行网页跳转 原因分析 在嵌入的src地
  • 车牌识别系统Matlab算法实现

    车牌识别系统Matlab算法实现 标签 车牌识别 2014 10 29 10 51 1408人阅读 评论 0 收藏 举报 本文章已收录于 分类 机器学习 21 作者同类文章 X plain view plain copy print
  • MindSpore报错“TypeError: parse() missing 1 required positional.“

    1 报错描述 1 1 系统环境 ardware Environment Ascend GPU CPU CPU Software Environment MindSpore version source or binary 1 6 0 Pyt
  • C++知识整理系列(三)—— constexpr常量表达式

    const修饰常量 但是const并未区分编译时常量和运行时常量 而constexpr则只能是编译时常量 在C 11中提出 这篇文章 将详细讲解constexpr 目录 一 常量表达式 二 constexpr变量 三 constexpr函数