C++ static_assert 编译期断言
先回顾普通 assert
普通 assert 用于在程序运行时检查条件。
#include <cassert>
int main() {
int x = 10;
assert(x > 0);
}
条件为假时,程序会在运行时终止。因此,assert 属于运行期检查。
什么是 static_assert
static_assert 用于在编译阶段检查条件。
static_assert(条件, "错误信息");
例如:
static_assert(sizeof(int) >= 4,
"int 类型至少需要 4 字节");
条件为假时,程序无法通过编译。
条件必须能在编译期确定
正确:
constexpr int size = 10;
static_assert(size > 0, "size 必须大于 0");
错误:
int size;
std::cin >> size;
static_assert(size > 0, "size 必须大于 0");
第二段中的 size 只有运行后才能确定,因此不能用于 static_assert。
C++17 的简化写法
在较早标准中通常需要写错误信息:
static_assert(sizeof(int) >= 4, "int 太小");
从 C++17 开始,可以省略第二个参数:
static_assert(sizeof(int) >= 4);
不过实际开发中,保留错误信息更方便定位问题。
常见用途
检查类型大小
static_assert(sizeof(long long) >= 8,
"long long 至少需要 8 字节");
检查模板参数
template <typename T>
T add(T a, T b) {
static_assert(sizeof(T) >= 4,
"类型长度不能小于 4 字节");
return a + b;
}
结合类型特征
#include <type_traits>
template <typename T>
T twice(T value) {
static_assert(std::is_integral_v<T>,
"T 必须是整数类型");
return value * 2;
}
调用:
twice(10); // 正确
twice(3.14); // 编译错误
检查数组长度
template <typename T, std::size_t N>
void process(T (&arr)[N]) {
static_assert(N >= 5,
"数组长度至少为 5");
}
检查配置常量
constexpr int BufferSize = 1024;
static_assert(BufferSize > 0,
"缓冲区大小必须大于 0");
static_assert((BufferSize & (BufferSize - 1)) == 0,
"缓冲区大小必须是 2 的幂");
与 assert 对比
| 项目 | assert | static_assert |
| 检查时间 | 运行时 | 编译时 |
| 条件要求 | 普通布尔表达式 | 常量表达式 |
| 失败结果 | 程序终止 | 编译失败 |
| 是否需要头文件 | <cassert> | 不需要 |
| 典型用途 | 检查运行数据 | 检查类型和配置 |
常见错误
使用运行时变量
int x = 10;
static_assert(x > 0, "x 必须大于 0"); // 错误
如果要检查运行时数据,应使用普通判断或 assert。
条件和错误信息矛盾
错误:
static_assert(sizeof(int) < 4,
"int 至少应有 4 字节");
正确:
static_assert(sizeof(int) >= 4,
"int 至少应有 4 字节");