static_assert在编译期检查常量表达式是否为true,若为false则编译失败;它仅作用于编译期可求值的表达式,如字面量、constexpr变量、类型特征等,不接受运行时值。

static_assert 在编译期检查什么
它只在编译时起作用,用来验证一个常量表达式是否为 true。一旦不成立,编译直接失败,不会生成目标文件。这和 assert(运行时)有本质区别——static_assert 检查的是类型、模板参数、字面量计算等能在编译期确定的东西。
常见误用是拿它去判断变量值或函数返回值,比如 static_assert(x > 0)(x 是普通变量),这会报错:error: static assertion failed,因为 x 不是常量表达式。
- 只能用于常量表达式:字面量、
constexpr变量、类型特征(如std::is_same_v<t int></t>)、模板参数推导结果 - 不能依赖运行时信息:指针值、非
constexpr函数调用、未初始化的const变量 - 错误信息字符串是可选的,但强烈建议写:没它的话,编译器只报“failed”,很难定位问题
模板中用 static_assert 限制类型
这是最典型也最有价值的场景。比如你写了一个只支持整数的容器模板,想在用户传入 std::string 时立刻报错,而不是等到实例化出一堆晦涩的模板展开错误。
template<typename T>
class IntOnlyStack {
static_assert(std::is_integral_v<T>, "T must be an integral type");
// ...
};注意:std::is_integral_v 是 C++17 引入的变量模板,比老式的 std::is_integral<T>::value 更简洁;如果用旧标准,记得加 ::value。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 放在类/函数体开头最稳妥,避免成员定义或函数体先被解析导致意外行为
- 多个约束可用逻辑与组合:
static_assert(std::is_integral_v<T> && sizeof(T) <= 8, "...") - 别依赖未声明的类型别名或
decltype表达式,除非确保它们在断言位置已可见
检查常量表达式和编译期计算
比如验证数组大小是否对齐、枚举值是否落在预期范围内、或者两个类型大小关系是否符合假设。
constexpr size_t BUFFER_SIZE = 4096;
static_assert(BUFFER_SIZE % 64 == 0, "BUFFER_SIZE must be multiple of cache line");
<p>enum class Status { OK = 0, ERROR = 1 };
static_assert(static_cast<int>(Status::ERROR) == 1, "Status enum layout broken");这类断言容易被忽略的是:某些计算看似常量,实则依赖未完全定义的内容。例如在类定义内部引用自身 sizeof,在类尚未完成定义前是非法的。
-
sizeof、alignof、字面量运算都安全,但仅限于完整类型 - 避免在类定义体内使用
sizeof(MyClass)—— 此时MyClass还没定义完 - 宏定义的数值可以参与,但宏展开后必须是合法常量表达式(比如不能含
sizeof非完整类型)
跨平台或 ABI 兼容性校验
当你需要确保结构体布局在不同编译器或平台上一致,static_assert 能提前拦截风险。
struct Header {
uint32_t magic;
uint16_t version;
uint16_t flags;
};
static_assert(sizeof(Header) == 8, "Header size mismatch - check packing");
static_assert(offsetof(Header, version) == 4, "Header field offset changed");这里的关键是:offsetof 和 sizeof 在标准布局类型(standard-layout type)上是常量表达式,所以能进 static_assert。但如果结构体用了虚函数、非公有继承或非公有成员,就不是标准布局,offsetof 就不能用。
- 务必确认类型满足标准布局要求(
std::is_standard_layout_v<T>)再用offsetof - 结构体对齐受
#pragma pack或alignas影响,断言要覆盖这些配置变化 - 不要只断言总大小,字段偏移同样关键——小端/大端不影响
offsetof,但会影响序列化兼容性
最难绷的是,有些断言看似合理,却因模板实例化顺序或 SFINAE 上下文被静默跳过。真遇到断言没触发,先检查它是否处在被丢弃的模板分支里。

















