Static assert 是一种编译器机制,用于在编译阶段生成错误,如果表达式(条件)不满足。此功能自C++11引入,旨在简化模板编程并提高代码质量。
问题历史。
在static_assert出现之前,程序员使用诸如负数组大小的结构(如 char arr[condition?1:-1];)等技巧,这种做法的可读性较差,并且不方便用于错误诊断。因此,出现了对具有有意义消息的编译时错误显式声明的需求。
问题。
在模板编程中,常常需要进行早期诊断(例如,禁止创建不适合的类型或参数的对象)。没有静态检查,这些错误只会在最终代码编译阶段出现(有时是突发且难以解释的错误)。
解决方案。
关键字 static_assert 接受一个布尔表达式和一条消息字符串。如果表达式为假,编译将以错误结束并输出消息。
代码示例:
static_assert(sizeof(int) >= 4, "int must be at least 4 bytes"); template<typename T> void foo(const T& obj) { static_assert(std::is_copy_constructible<T>::value, "T must be copy-constructible"); }
关键特点:
可以在没有第二个参数的情况下使用static_assert吗?
可以,自C++17起,第二个参数是可选的:
static_assert(sizeof(double) == 8); // 默认消息
如果条件依赖于模板参数,但模板未实例化,static_assert表达式是否会被执行?
不会,static_assert只有在达到实例化点时才会触发,这允许对只使用的模板进行检查。
可以在static_assert内部使用运行时(run-time)表达式吗?
不可以,表达式必须在编译阶段可计算(constexpr)。如果表达式不是constexpr,则会出现编译错误。
在代码中使用了具有运行时计算的表达式的static_assert(例如,读取输入时的文件大小),这导致系统出现了不明确的编译错误。
优点:
缺点:
需要保证模板Matrix只能与Plain Old Data(POD)类型一起创建,排除复杂结构。
template<typename T> class Matrix { static_assert(std::is_pod<T>::value, "Matrix can be instantiated only for POD types"); // ... };
优点:
缺点: