const 表示运行期不要改这个对象:初始化之后不能再赋值。constexpr 更进一步:值或函数结果可以在编译期就算出来,用来当数组长度、模板参数。constexpr 函数在实参是运行期变量时仍可在运行期调用;C++20 的 consteval 则强制只能在编译期调用。本节先写出可运行的 const 与 square,再对照三者。指针上的 const 位置见指针。
const:只读
形参写成 const std::string&,既避免拷贝,又禁止函数里改调用方的字符串。指向常量的指针 const int* 不能通过指针改所指对象;对象自己若不是 const,仍可通过原变量改。
#include <iostream>
int main() {
int value = 10;
const int* q = &value; // 不能写 *q = 20
value = 20; // 通过原变量改仍然可以
std::cout << *q << "\n";
return 0;
}输出:
20类的 const 数据成员只能在构造函数的初始化列表里赋值,函数体内不能再改,见构造函数。
constexpr:编译期可求值
constexpr int area = square(10) 在编译期就算好。square(side) 里 side 是普通变量,同一函数改在运行期算,仍然合法。
#include <iostream>
constexpr int square(int x) {
return x * x;
}
int main() {
constexpr int area = square(10);
int side = 5;
std::cout << area << " " << square(side) << "\n";
return 0;
}输出:
100 25不能把运行期才知道的量赋给 constexpr 变量,例如用 cin 读进来的数去初始化 constexpr int n,无法通过编译。
怎么选
- 只要不可变,用
const。上限可以来自配置文件,运行期初始化即可。 - 要用在数组长度、
static_assert、模板非类型参数上,用constexpr。 constexpr已经包含只读含义,再写一层const合法但多余。
了解:consteval 与 static_assert
consteval 函数必须在编译期调用:compile_only(7) 可以,compile_only(x) 而 x 是普通变量则非法。static_assert(square(10) == 100) 在编译期检查条件,失败则直接报错。深度用法可在掌握模板后再展开。
本节说明了只读修饰与编译期求值的分工。下一节介绍auto 与 decltype:由编译器推导类型时的规则与常见陷阱。