先来看看constexpr与常量表达式
常量表达式
1. 什么是常量表达式
常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。 显然,字面值属于常量表达式, 用常量表达式初始化的const对象也是常量表达式。
const int maxCount = 10; // 常量表达式
const int limit = maxCount + 1; // 常量表达式
int arraySize = 20; // 他的数据类型只是一个普通int, 不是常量表达式
const int sz = get_size(); // sz的值直到运行时才会获取到, 因此不是常量表达式
2.constexpr变量
在一个复杂的系统中, 很难分辨一个初始值到底是不是常量表达式。当然可以定义一个const变量并把它的初始值设为我们认为的某个常量表达式, 但在实际使用时, 尽管要求如此,却常常发现初始值并非常量表达式的情况。 可以这么说, 在此种情况下, 对象的定义和使用根本就是两回事。
c++11新标准规定, 允许将变量声明为constexpr类型以由编译器来验证变量的值是否是一个常量表达式。 声明为constexpr的变量一定是一个常量, 而且必须用常量表达式初始化。
constexpr int mf = 20; // 20是常量表达式
constexpr int limit = mf + 1; // mf+1是常量表达式
constexpr int sz = size(); // 只有当size是一个constexpr函数时才是一条正确的声明语句
不能使用普通函数作为constexpr变量的初始值, 但是新标准允许定义一种特殊的constexpr函数。这种函数应该足够简单以使得编译时就可以计算其结果, 这样就能用constexpr函数去初始化constexpr变量了。
3.字面值类型
常量表达式的值需要在编译时就得到计算, 因此对声明constexpr时用到的类型必须有所限制。 因为这些类型一般比较简单, 值也显而易见、容易得到, 就把它们称为“字面值 类型”
字面值类型包括:算数类型、引用和指针、字面值常量类、枚举
尽管指针和引用都能定义成constexpr, 但它们的初始值却受到严格限制。一个constexpr指针的初始值必须是nullptr或者0,或者是存储于某个固定地址中的对象。
定义于所有函数体之外的对象其地址固定不变, 能用来初始化constexpr指针。同样, 定义在函数中的static变量也有固定地址, 因此constexpr引用能绑定到这样的变量上,constexpr指针也能指向这样的变量。
指针和constexpr
在constexpr声明中如果定义了一个指针, 限定符constexpr仅对指针有效, 与指针所指的对象无关。
const int *p = nullptr; // p是一个指向整型常量的指针
constexpr int *q = nullptr; // q是一个指向整数的常量指针
与其他常量指针类似, constexpr指针既可以指向常量, 也可以指向一个非常量,指向常量时, 格式为
constexpr const type *p = xxx;
constexpr int *np = nullptr;
int j = 0;
constexpr int i = 42;
constexpr const int *p = &i; // p是常量指针,指向整数常量i
constexpr int *p1 = &j; // p1是常量指针,指向整数j
上面的i和j必须满足地址固定不变的条件, 经过尝试, 如果定义在main函数中, 在mingw中会报错, 而在vs中不报错