static_assert必须带字符串字面量,C++11起规范强制要求第二参数为字符串,否则编译失败;旧版GCC如4.7会直接报错且无位置信息,调试困难。

static_assert 为什么必须带字符串字面量
不加错误提示字符串,static_assert 在某些编译器(比如旧版 GCC)会直接报错,不是警告——它根本不是可选参数,而是语法强制要求。C++11 起规范明确要求第二个参数必须是字符串字面量,否则编译失败。
- 错误写法:
static_assert(sizeof(int) == 4);→ GCC 4.7– 报error: static assertion failed且无位置信息,调试困难 - 正确写法:
static_assert(sizeof(int) == 4, "int must be 4 bytes"); - 字符串内容不用太长,但得让团队成员一眼看懂哪条约束崩了,比如
"expected little-endian platform"比"check endianness"有用得多
模板里用 static_assert 检查类型是否支持某操作
靠 decltype + std::declval 组合,能实现在实例化时就捕获“调用不存在函数”的错误,比 SFINAE 更直白、比运行时报错更早。
- 常见场景:模板函数要求传入类型有
.size()成员函数,但用户传了int或裸指针 - 写法示例:
template <typename T> void process(const T& t) { static_assert(std::is_same_v<decltype(t.size()), size_t>, "T must have .size() returning size_t"); } - 注意:
decltype(t.size())会触发 ADL,如果T重载了size为非成员函数,也可能通过;想严格限定为成员函数,得配合std::is_member_function_pointer等进一步约束
static_assert 和 constexpr 函数搭配做复杂编译期验证
单纯比较常量表达式太单薄,真正有用的检查往往要算点东西——比如验证某个数组长度是否为 2 的幂、结构体字段偏移是否对齐、甚至 CRC 校验值是否匹配。
- 必须用
constexpr函数,普通函数即使参数全为字面量也不行;C++14 起支持更宽松的constexpr函数体(允许循环、局部变量) - 示例:检查缓冲区大小是否为页对齐
constexpr bool is_power_of_two(size_t n) { return n != 0 && (n & (n - 1)) == 0; } static_assert(is_power_of_two(4096), "buffer size must be power of two"); - 坑点:递归深度超限(如写错终止条件)会导致编译器报
constexpr evaluation exceeded maximum depth,不是语法错,容易误判为环境问题
跨平台代码里 static_assert 容易漏掉的隐式类型陷阱
Windows 下 long 是 4 字节,Linux x86_64 下是 8 字节;time_t 在 32 位系统可能是 int,64 位下常为 long long。这些差异不会在代码里显式写出,但 static_assert 能第一时间暴露。
立即学习“C++免费学习笔记(深入)”;
- 推荐检查项:
static_assert(sizeof(void*) == 8, "64-bit pointer expected")、static_assert(std::is_signed_v<decltype>, "time_t must be signed")</decltype> - 别只信头文件注释,
sizeof和std::is_*_v查的是实际 ABI,这才是链接前的真实约束 - CI 构建时记得覆盖目标平台组合(如 mingw-x86_64、aarch64-linux-gnu),否则
static_assert就成了摆设
最麻烦的不是写不对 static_assert,而是它通过了,但你检查的表达式本身依赖未定义行为——比如对未初始化的 constexpr 变量取值,或在常量求值中用了 reinterpret_cast。这种时候编译器可能静默接受,直到换编译器版本才崩。


















