断言简述
断言(assertion)是编程中的一种常用手段,在通常情况下,断言就是将一个返回值总是真(或者我们需要是真)的判别式放在语句中,用以排除在设计逻辑上不应该出现的情况。举个例子:我们都知道除数不能为0,那么就可以对除数使用断言,以使程序在除数为0的情况下产生异常退出。
通常来说,断言并不是正常程序所必需的,但对于程序调试来说,通常断言能够帮助开发者快速定位那些违反了某些前提条件的程序错误。在C++中,头文件<cassert>提供了assert宏,提供运行时断言。如下:
#include <cassert>
double Sub(int dividend, int divisor)
{
assert(divisor != 0); //断言,除数必须大于0
return static_cast<double>(dividend)/static_cast<double>(divisor);
}
上述代码中对除数使用了断言,当除数为0时程序会报错。
然而,前述的断言只能在运行时才会起作用,这意味着不运行程序我们不会知道程序是否有错,而且就算运行了也只有在的调用到assert相关的代码路径时才会检查出来,这再某些情况下是不可接受的。因此我们还需要(特别是在模板编程中)在编译时期就能产生断言的机制。为此,C++11推出了静态断言。
静态断言
C++的静态断言语法很简单,也可以自定义错误提示信息:
static_assert(bool_constexpr, message) 从C++11起
static_assert(bool_constexpr) 从C++17起
第二种断言定义方式并不意味着前述的assert失去了作用,因为static_assert的第一个参数必须是常量表达式,这样才能实现编译时断言。当我们只需要运行时断言时,还是得使用assert而不是static_assert。另外,第二个参数message必须是字符串字面值,这一点在使用的时候也需要注意。
使用静态断言,我们可以在编译期间发现更多的错误,用编译器来强制保证一些契约,并帮助我们改善编译信息的可读性(用过BOOST_STATIC_ASSERT就能体会到这点),尤其是在使用模板的时候。
如前面所说,编译器将第一个参数作为常量表达式来执行断言,但如果该常量表达式依赖于某些模板参数,则延迟到模板实例化时再执行,这就让检查模板参数成为了可能。
static_assert的另一个好处是,因为是编译期断言,不生成目标代码,因此使用static_assert不会造成任何运行期性能损失。