编程C++开发者

什么是C++中的const-expressions (constexpr)?在什么情况下和为什么使用它们,它们与宏和const有什么不同?

用 Hintsage AI 助手通过面试

答案

问题的历史

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; // 可以,在编译时计算

常见错误和反模式

  • 混淆const和constexpr
  • 尝试在C++14之前的constexpr函数中使用复杂逻辑结构
  • 在constexpr上下文中错误地使用非常量变量

生活中的例子

负面案例

开发者使用#define PI 3.14进行所有圆面积的计算。

优点:

  • 编写简单

缺点:

  • 没有类型安全,可能导致替换错误
  • 无法在模板或数组参数中用作constexpr

正面案例

开发者使用constexpr double PI = 3.141592653589793;和模板constexpr函数进行计算。

优点:

  • 类型安全
  • 编译时优化
  • 使用的通用性(例如,在模板中)。

缺点:

  • 对代码理解的要求稍高;需要支持C++11+