constexpr允许在编译期计算表达式或函数,提升性能与安全性,其核心是标记变量和函数以实现编译期求值,相比const更强调编译期可能性,而consteval要求必须编译期求值,constinit确保静态变量的常量初始化。

C++的
constexpr
constexpr
在我看来,
constexpr
constexpr
首先,对于变量,它的用法很简单:只要一个变量的值能在编译时确定,你就可以用
constexpr
constexpr int max_size = 1024; // max_size在编译时就确定是1024 constexpr double pi = 3.1415926535; // pi也是编译期常量
这样定义的变量,编译器会确保它们是编译期常量。如果尝试用一个运行时才能确定的值去初始化
constexpr
立即学习“C++免费学习笔记(深入)”;
更强大的是
constexpr
constexpr
constexpr
constexpr
return
constexpr
for
while
if
switch
constexpr
constexpr
try-catch
std::vector
我们来看一个C++14风格的
constexpr
#include <iostream>
// C++14 风格的 constexpr 阶乘函数
constexpr long long factorial(int n) {
if (n < 0) {
// 在编译期,如果 n 是负数,这里会引发编译错误
// 对于运行时调用,这会是一个运行时错误,但 constexpr 的意义在于它能检查编译期常量
// throw std::out_of_range("Factorial argument must be non-negative"); // C++20 允许 throw
// C++14/17 时代通常会返回一个特殊值或依赖于编译期检查
return 0; // 或者引发编译期错误,例如通过 static_assert
}
long long res = 1;
for (int i = 2; i <= n; ++i) {
res *= i;
}
return res;
}
int main() {
// 编译期计算
constexpr long long f5 = factorial(5); // 编译器直接算出 120
std::cout << "Factorial of 5 (compile-time): " << f5 << std::endl;
// 编译期计算,用于数组大小
int arr[factorial(4)]; // 数组大小在编译期确定为 24
std::cout << "Array size: " << sizeof(arr) / sizeof(int) << std::endl;
// 运行时计算
int num = 6;
long long f_runtime = factorial(num); // num 是运行时变量,函数在运行时执行
std::cout << "Factorial of 6 (run-time): " << f_runtime << std::endl;
// 尝试在编译期传入非法值 (C++14/17 可能会编译失败,C++20 允许 throw 并在编译期捕获)
// constexpr long long f_neg = factorial(-1); // 这通常会导致编译错误
// 比如:error: call to 'factorial' is not a constant expression
// 因为 factorial(-1) 在编译期无法返回一个有效常量,且其内部逻辑不被视为常量表达式。
// 具体行为取决于编译器实现和 C++ 标准版本。
return 0;
}在这个例子中,
factorial(5)
factorial(4)
factorial(num)
constexpr
我个人觉得,编译期常量计算,也就是
constexpr
其次,它极大地增强了类型安全和错误检测。如果一个计算在编译期就能完成,那么任何潜在的错误——比如除以零、数组越界(如果能通过
constexpr
再者,编译期常量计算是现代C++高级特性的基石。没有
constexpr
constexpr
PI
constexpr double PI = 3.14159;
#define PI 3.14159
最后,它还能带来一些内存优化。编译期常量通常可以存储在只读数据段,这在某些架构上可以减少运行时内存的写操作,甚至可能在某些情况下优化缓存利用率。虽然这可能不是最主要的驱动因素,但也是一个不错的附带好处。
constexpr
const
consteval
constinit
这几个关键字,虽然都和“常量”或“编译期”沾边,但它们的侧重点和语义却大相径庭,理解它们之间的差异,对于写出高质量的C++代码至关重要。在我看来,它们形成了一个从“只读”到“必须编译期求值”的谱系。
const
const
const
const int x = runtime_function();
const
constexpr
constexpr
const
constexpr
consteval
constexpr
consteval
consteval
consteval int get_magic_number() { return 42; }
// int x = get_magic_number(); // OK,x是42
// int y = runtime_value;
// int z = get_magic_number() + y; // 编译错误!get_magic_number() 必须在编译期求值constinit
constinit
constinit
const
constinit int global_value = 100; // 确保在静态初始化阶段初始化 // global_value = 200; // 允许修改
总结一下,
const
constexpr
consteval
constinit
constexpr
在我的项目经验中,
constexpr
constexpr
替代宏定义,定义类型安全的常量和配置: 这是最直接,也是最应该做的。很多老旧代码喜欢用
#define
#define MAX_BUFFER_SIZE 1024
constexpr
// 替代 #define MAX_SIZE 1024 constexpr int MAX_BUFFER_SIZE = 1024; constexpr double GOLDEN_RATIO = 1.6180339887;
编写小型、纯粹的工具函数: 很多数学计算、单位转换、哈希函数等,如果它们的输入是编译期常量,那么结果也通常可以在编译期确定。将这些函数标记为
constexpr
// 编译期字符串哈希
constexpr unsigned long long hash_str(const char* str) {
unsigned long long hash = 5381;
while (*str) {
hash = ((hash << 5) + hash) + static_cast<unsigned char>(*str++);
}
return hash;
}
// 在 switch case 中使用编译期哈希
void process_command(const char* cmd) {
switch (hash_str(cmd)) {
case hash_str("start"):
std::cout << "Starting..." << std::endl;
break;
case hash_str("stop"):
std::cout << "Stopping..." << std::endl;
break;
default:
std::cout << "Unknown command." << std::endl;
}
}编译期验证和断言: 利用
constexpr
assert
static_assert
constexpr bool is_power_of_two(int n) {
return (n > 0) && ((n & (n - 1)) == 0);
}
// 编译期验证
static_assert(is_power_of_two(16), "16 should be a power of two!");
// static_assert(is_power_of_two(15), "15 is not a power of two!"); // 这会导致编译错误与模板元编程(TMP)结合:
constexpr
constexpr
if constexpr
template <typename T>
constexpr T get_default_value() {
if constexpr (std::is_integral_v<T>) { // C++17 if constexpr
return 0;
} else if constexpr (std::is_floating_point_v<T>) {
return 0.0;
} else {
return T{}; // 其他类型使用默认构造
}
}
// 使用
int i = get_default_value<int>(); // i = 0
double d = get_default_value<double>(); // d = 0.0构建编译期数据结构(C++20及更高版本): 随着C++标准对
constexpr
std::string
std::vector
当然,在使用
constexpr
constexpr
constexpr
以上就是C++constexpr实现编译期常量计算方法的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号