[原创]C++基础系列—const和constexpr

constant 意思是”常量”, 而 const 和 constexpr 这两个关键字和 constant 有一定的关系。常量的广义定义是:不变化的量(比如:重力加速度,圆周率,光速等)。说这两个关键字之前,我们还得提一下同样可以定义常量的关键字:#define

#define

你可能见过如下代码:

# include <stdio.h>
# define PI 3.14
int main(void)
{
    float s;
    s = PI * 5 * 5;
    printf("s = %.6f\n", s);
    return 0;
}

此时,PI 的作用就是一个常量。这样写的好处是凡是代码中用到圆周率计算的地方,直接用 PI 替换,要扩展圆周率的精度,只要修改 PI 的值就行。#define定义常量也有一些问题:

  • #define 是宏,它仅仅是做字符匹配替换,没有语法检测;而且替换以后通常是纯右值,无法当作变量使用
  • 无作用域,容易字符冲突(比如:Max,Min)

当然,#define 也有以下一些优势:

  • 防止头文件重复包含(#ifndef XXX #define XXX #endif)
  • 条件编译(ifdef XXX… #else …#endif)

const

const关键字,其实有两种语义

  • 表示常量 const float PI = 3.14f
  • 修饰的对象不可改变

const也可以修饰函数,表示当前函数不允许修改被调用对象的值(注意: const 函数内不可调用非 const 函数)

const还可以修饰指针,它所在的位置不同,语义也有不同(*左定值,*右定向) :

  • 修饰指针指向的内容,则内容为不可变量 const int* p = &a; *p =3; //error
  • 修饰指针,则指针为不可变量 int* const p = &a; p = &b; //error

在C++11引入constexpr以后,官方不推荐用const表示常量,因此也可”片面”的认为,const关键字其实就是C#的关键字:readonly

constexpr

这是在C++11引入的关键字,在C++20以后,限制就越来越少,甚至可以修饰 lamda 表达式。它和const最主要的区别是:constexpr所修饰的常量必须是编译期常量(注意:constexpr 所修饰的函数,返回值则不一定要求是编译期常量),如下代码:

const int len = 5; //不推荐
constexpr int len = 5; //推荐
int a[len];

len是一个编译期就需要知道的常量,const 并不一定编译期就可获取它的值,因此严谨的写法应该是下面那种。至于constexpr的其他用处,那就得在元编程中大显身手了,这不在本篇基础文章讲解范围内