static_assert用于编译期断言,要求第一参数为constexpr bool表达式、第二参数为字符串字面量;仅在常量表达式可求值时触发,不可用于运行时变量或含未定义行为的表达式。

static_assert 的基本用法和触发条件
编译期断言必须在编译器能确定真假的常量表达式上工作,否则会报错 error: static assertion failed。它不能用于运行时变量、函数调用(除非是 constexpr 函数)、或未初始化的模板参数。
-
static_assert第一个参数必须是constexpr bool表达式,第二个参数(可选)必须是字符串字面量 - 放在函数体内部、类定义内、命名空间作用域都合法;但不能出现在 return 语句后或非定义上下文(如声明-only 头文件中未实例化的模板里)
- 常见误写:
static_assert(sizeof(int) == 4, "int must be 4 bytes");看似合理,但在某些平台(如嵌入式)可能失败——这不是 bug,而是你主动暴露了平台假设
模板中用 static_assert 检查类型约束
这是最实用的场景:防止错误类型传入模板,比 SFINAE 或 C++20 concepts 更早报错、信息更直白。
- 检查是否为整型:
static_assert(std::is_integral_v<t>, "T must be an integral type");</t> - 检查对齐要求:
static_assert(alignof(T) >= 8, "T must be at least 8-byte aligned"); - 注意
std::is_same_v和std::is_base_of_v返回的是编译期常量,适合这里;但typeid(T).name()不行,它不是 constexpr - 如果断言写在模板定义里但未实例化,编译器通常不检查——只有真正用到该特化时才触发
避免依赖未定义行为的常量表达式
看似合法的 constexpr 表达式,可能因未定义行为(UB)导致 static_assert 被跳过或行为异常。
- 不要写
static_assert(p != nullptr && *p == 42, "...")——p是指针变量,即使为 constexpr,解引用空指针仍是 UB,整个表达式不再是合法常量表达式 - 数组越界访问、有符号整数溢出、未初始化 constexpr 变量读取,都会让条件变成非良构(ill-formed),编译直接失败,而不是“断言失败”
- 安全做法:只用标准库提供的
std::is_*类型特征、字面量、sizeof/alignof、以及你自己写的明确标记为constexpr且无副作用的函数
C++11 到 C++20 的兼容性细节
早期标准对 static_assert 支持有限,跨编译器时容易踩坑。
立即学习“C++免费学习笔记(深入)”;
- C++11 要求第二个参数必须是字符串字面量(
"..."),不能是宏展开结果或 constexpr 字符串变量;Clang 3.5+ 和 GCC 4.9+ 才较好支持 - C++17 允许第二个参数为空字符串:
static_assert(cond);,但 MSVC 2017 之前仍要求显式字符串 - C++20 引入了
std::source_location,但static_assert仍不支持动态生成消息——别试图用std::format或字符串拼接构造提示信息 - 若需最大兼容性,统一用
static_assert(cond, "meaningful message");,并确保 message 是纯 ASCII 字符串字面量


















