C++20都支持虚函数的constexpr了,我打算用三篇读文章讲清楚编译期常量和constexpr这个东西和编译期常量的关系,即为什么需要他来辅助解决这个问题。最后帮助读者在实际编码过程中能够有意识地去运用他们,这才是终极目标。这篇文章中会讲到隐藏在日常编程中的各种编译期常量,以及他们存在的意义。

从编译期常量谈起

想要用编译期常量就要首先知道它们是什么,一般出现在哪里和运行期常量有什么区别,因此我打算用第一篇文章重点分析编译期常量以及使用他们有什么好处。

编译期常量(Compile-time constants)是C++中相当重要的一部分,整体而言他们有助提高程序的正确性,并提高程序的性能。这篇文章中出现的编译期常量都是在C++11之前就可以使用的,constexpr是C++11的新特性,所以各位不要有心理包袱。

总有些东西是编译器要求编译期间就要确定的,除了变量的类型外,最频繁出现的地方就是数组、switch的case标签和模板了。

数组中的编译期常量

如果我们想要创建一个不是动态分配内存的数组,那么我们就必须给他设定一个size——这个size必须在编译期间就知道,因此静态数组的大小是编译期常量。

int 

只有这么做,编译器才能准确地解算出到底要分配给这个数组多少内存。如果这个数组在函数中,数组的内存就会被预留在该函数的栈帧中;如果这个数组是类的一个成员,那么编译器要确定数组的大小以确定这个类成员的大小——无论哪种情况,编译器都要知道这个数组具体的size。

有些时候我们不用显示得指明数组的大小,我们用字符串或花括号来初始化数组的时候,编译器会实现帮我们数好这个数组的大小。

int 

模板中的编译期常量

除了类型以外,数字也可以作为模板的参数。这些数值变量包括int,long,short,bool,char和弱枚举enum等。

enum 

Case labels

既然编译器在初始化模板的时候必须知道模板的类型,那么这些模板的参数也必须是编译期常量。

switch语句的分支判断也必须是编译期常量,和上边模板的情况非常类似。

void 

使用编译期常量有什么好处

如果编译期常量的使用方法只有上边呈现的几种,那你大概会感觉有些无聊了。事实上,关于编译期常量我们能做的事情还有许多,他们能帮助我们去实现更高效的程序。

更安全的程序

编译期常量能让我们写出更有逻辑的代码——在编译期就体现出逻辑。比如矩阵相乘:

class 

我们都知道,两个矩阵相乘,当且仅当左矩阵的列数等于右矩阵的行数,如果不满足这个规则的话,那就完蛋了,所以针对上边矩阵的乘法,我们在函数中要做一些判断:

Matrix 

但是如果我们在编译期就知道了矩阵的size,那么我们就可以把上边的判断放在模板中完成——这样的话不同size的矩阵一下子就成了不同类型的变量了。这样我们的矩阵乘法也相应变得简单了一些:

template 

在这个例子中,编译器本身就阻止了错误的发生,还有很多其他的例子——更复杂的例子在编译期间使用模板。从C++11后有一堆这样的模板都定义在了标准库STL中,这个之后再说。所以大家不要觉得上边这种做法是脱裤子放屁,相当于我们把运行时的条件判断交给了编译期来做,前提就是矩阵的类型必须是编译期常量。你可能会问,除了像上边直接用常数来实例化矩阵,有没有其他方法来告诉编译器这是个编译期常量呢?请往下看。

编译优化

编译器能根据编译期常量来实现各种不同的优化。比如,如果在一个if判断语句中,其中一个条件是编译期常量,编译器知道在这个判断句中一定会走某一条路,那么编译器就会把这个if语句优化掉,留下只会走的那一条路。

if 

在上例中,编译器就会直接利用其中某一个cout语句来替换掉整个if代码块——反正运行代码的机器是32还是64位的又不会变。 另一个可以优化的地方在空间优化。总体来说,如果我们的对象利用编译期常数来存储数值,那么我们就不用在这个对象中再占用内存存储这些数。就拿本文之前的例子来举例:

  • someStruct结构中包含一个‘unsigned long’,一个‘char’,和一个‘color’,尽管如此他的实例对象却只占用一个byte左右的空间。
  • 矩阵相乘的时候,我们在矩阵中也没必要花费空间去存储矩阵的行数和列数了。

结语

这一篇文章只讲到了编译期常量,为了使编译器在编译期间计算出常量,我们在C++11标准之前和之后都采用了不同的方法去实现它。在第二篇文章中,我会将主要精力放在C++11标准之前的编译期计算的问题,通过展现一系列蹩脚的方法来引出我们的主角——constexpr。

该系列的第二篇已经出来啦!点赞收藏后走这里哈:

小天狼星不来客:C++干货系列——从编译期常量谈到constexpr(二)​zhuanlan.zhihu.com


这篇文章收录在我的专栏中哦:

C++干货系列​zhuanlan.zhihu.com

点个关注,及时获得最新干货。

运行时常量池在哪里_C++干货系列——从编译期常量谈到constexpr(一)相关推荐

  1. 1.2 - C#语言习惯 - 用运行时常量readonly而不是编译期常量const

    C#中有两种类型的常量:编译期常量和运行时常量.二者有着截然不同的行为,使用不当将会带来性能上或正确性上的问题. 这两个问题最好都不要发生,不过若难以同时避免的话,那么一个略微慢一些但能保证正确的程序 ...

  2. java 编译期常量

    今天在看书的时候遇到了一个不是很懂的名词,是在think in java 这本书的第七章讲final关键字时讲到的.然后自己在网上查了一下知道了一些. 编译器常量就是:它的值在编译期就可以确定的常量. ...

  3. integral_constant定义编译期常量

    #include  "stdafx.h" #include <iostream> #include <type_traits>   using  names ...

  4. char类型的实参与const char类型的形参不兼容_C++干货系列——顶层const和底层const...

    顶层 const 和底层 const 学C++的小伙伴是不是被const机制搞得晕头转向,永远都记不住哪个是指针不能变哪个是指针指向的对象不能变?纯靠记忆肯定不行,理解透彻才能一劳永逸.本文详细介绍了 ...

  5. java class文件常量池_JAVA程序员谈谈class文件结构中的常量池-class文件

    常量的类型有12种 CONSTANT_Utf8_info1字面量UTF-8编码的字符串 CONSTANT_Integer_info3字面量整型字面量 CONSTANT_Float_info4字面量浮点 ...

  6. JVM - Class常量池 || 运行时常量池

    文章目录 Pre class常量池 字面量 符号引用 运行时常量池 Pre JVM - 深入剖析字符串常量池 JVM - 基本类型的包装类和对象池 class常量池 Class常量池我们可以理解为是C ...

  7. python 常量池_聊一聊让我蒙蔽一晚上的各种常量池

    在写之前我们先来看几个问题,假如你对这些问题已经很懂了的话,那大可不用看这篇文章,如果不大懂的话,那么可以看看我的想法. 问题1: public static void main(String[] a ...

  8. 深度剖析Java常量池

    Class常量池 class常量池可以理解为是Class文件中的资源仓库.Class文件中除了包含类的版本.字段.方法.接口等描述信息外,还有一项信息就是常量池(constant pool table ...

  9. 02.字符串常量池 ? class常量池? 运行时常量池?

    java对象创建流程: 简介: 这几天在看Java虚拟机方面的知识时,看到了有几种不同常量池的说法,然后我就去CSDN.博客园等上找资料,里面说的内容真是百花齐放,各自争艳,因此,我好好整理了一下,将 ...

最新文章

  1. 编程范式,程序员的编程世界观
  2. nginx反向代理取得IP地址
  3. JavaScript:Scope(域)的基本指南
  4. i7 8700 服务器系统,i7 8700k 云服务器6
  5. Python-selenium-操作元素
  6. 决策树算法小结(三) CART原理及代码实现
  7. redis 经典36问
  8. LINUX下载并编译sqlite
  9. 【旧文章搬运】深入分析Win7的对象引用跟踪机制
  10. 企业对计算机类专业人才培养方案,应用型本科计算机科学与技术专业人才培养方案探讨...
  11. JS:鼠标事件:实现鼠标移动到div背景颜色变换,移开还原
  12. java随机生成迷宫游戏地图_java随机生成迷宫(图的深度优先遍历)
  13. 佳能6d2无线链接计算机操作,玩转EOS 6D无线WiFi功能三步骤
  14. 固定偏置放大电路为何不能保证静态工作点的稳定性?
  15. Java实现DES加密解密(对称式)
  16. mysql order by 原理及优化详解
  17. 用友财务软件函数说明
  18. 亚马逊风控从哪些方面检测的?
  19. 深入了解StringBuilder和String
  20. python如何循环执行_python循环执行语句怎么写

热门文章

  1. QDU第一届程序设计大赛——E到I题解法(非官方题解)
  2. Python3 range()函数
  3. C#中的快捷键,可以更方便的编写代码
  4. binary search完整笔记
  5. 【LeetCode】13. Roman to Integer
  6. docker学习笔记(四): 镜像和仓库
  7. ZeroMQ接口函数之 :zmq_msg_init_data - 从一个指定的存储空间中初始化一个ZMQ消息对象的数据...
  8. POJ 2240 Arbitrage
  9. 若格式化都无效 如何清除”不可杀“病毒?
  10. AtlasControlToolkit.CascadingDropDownNameValue自定义用法