问题的历史
C++最初仅支持宏(#define)和常量(const)。但是,仅使用这些无法满足编译时定义值的需求。在C++11中引入了关键字constexpr,允许在编译阶段计算值,而不仅仅是在程序执行时。
问题
在constexpr出现之前,许多任务必须通过宏(粗糙的文本替换,没有类型安全)或const来解决,但const并不总是保证在编译阶段执行表达式。这增加了程序优化的难度,并导致了不可预测的行为。
解决方案
constexpr向编译器保证,声明的表达式将在可能的情况下在编译时计算。这用于声明可以安全有效地在编译时计算的函数、变量以及类的构造函数和方法。
代码示例:
constexpr int Square(int x) { return x * x; } constexpr int size = Square(5); // size在编译时计算 const int arr[size] = {}; // 可作为数组的大小使用
关键特点:
可以使用任何函数作为constexpr吗?
不可以。函数必须符合一定的限制:足够简单,包含一个return语句(在C++14之前),或只能包含常量表达式代码(从C++14及以后)。
constexpr int f(int x) { return x + 2; } // 可以 constexpr int g(int x) { int y = x + 2; return y; } // 在C++14之前:无法编译!之后可以
所有constexpr变量都能在编译时计算吗?
不可以。如果初始化时使用了非常量值或表达式无法在编译时计算,将产生错误。
int val; // constexpr int x = f(val); // 错误:val未初始化!
constexpr和const之间有什么区别?
const仅保证不可更改,但不保证在编译时计算。constexpr要求在编译时计算值(如果可能)。
const int x = time(nullptr); // 可以,但在运行时计算 constexpr int y = 42; // 可以,在编译时计算
开发者使用#define PI 3.14进行所有圆面积的计算。
优点:
缺点:
开发者使用constexpr double PI = 3.141592653589793;和模板constexpr函数进行计算。
优点:
缺点: