C++0x中引入了static_assert这个关键字,用来作编译期间的断言,所以叫作静态断言。函数
其语法:static_assert(常量表达式,提示字符串)。性能
若是第一个参数常量表达式的值为false,会产生一条编译错误,错误位置就是该static_assert语句所在行,第二个参数就是错误提示字符串。spa
使用static_assert,咱们能够在编译期间发现更多的错误,用编译器来强制保证一些契约,并帮助咱们改善编译信息的可读性,尤为是用于模板的时候。code
static_assert能够用在全局做用域中,命名空间中,类做用域中,函数做用域中,几乎能够不受限制的使用。blog
编译器在遇到一个static_assert语句时,一般马上将其第一个参数做为常量表达式进行演算,但若是该常量表达式依赖于某些模板参数,则延迟到模板实例化时再进行演算,这就让检查模板参数成为了可能。作用域
因为以前有望加入C++0x标准的concepts提案最终被否决了,所以对于检查模板参数是否符合指望的重任,就要靠static_assert来完成了,因此如何构造适当的常量表达式,将是一个值得探讨的话题。字符串
性能方面,因为是static_assert编译期间断言,不生成目标代码,所以static_assert不会形成任何运行期性能损失。get
简单范例:编译器
static_assert(sizeof(void *) == 4, "64-bit code generation is not supported.");
该static_assert用来确保编译仅在32位的平台上进行,不支持64位的平台,该语句能够放在文件的开头处,这样能够尽早检查,以节省失败状况下的编译时间。string
另外一个范例:
#include <cassert> #include <cstring> using namespace std; template <typename T, typename U> int bit_copy(T& a, U& b){ assert(sizeof(b) == sizeof(a));
//static_assert(sizeof(b) == sizeof(a), "template parameter size no equal!"); memcpy(&a,&b,sizeof(b)); }; int main() { int aaa = 0x2468; double bbb; bit_copy(aaa, bbb); getchar(); return 0; }
这里使用assert运行时断言,但若是bit_copy不被调用,咱们将没法触发该断言,实际上正确产生断言的时机应该在模版实例化时,即编译时期。
使用static_assert替换assert再次编译,便可得到一个错误并显示咱们指定的错误信息。
注意:static_assert的断言表达式的结果必须是在编译时期能够计算的表达式,即必须是常量表达式。若是使用变量,则会致使错误。
int positive(const int n) { static_assert(n > 0, "value must > 0"); return 0; }
咱们知道,C++现有的标准中,就有assert、#error两个设施,也是用来检查错误的,还有一些第三方的静态断言实现。
assert是运行期断言,它用来发现运行期间的错误,不能提早到编译期发现错误,也不具备强制性,也谈不上改善编译信息的可读性,既然是运行期检查,对性能固然是有影响的,因此常常在发行版本中,assert都会被关掉;
#error可看作预编译期断言,甚至都算不上断言,仅仅能在预编译时显示一个错误信息,它能作的很少,能够配合#ifdef/ifndef参与预编译的条件检查,因为它没法得到编译信息,固然就作不了更进一步分析了。
在stastic_assert提交到C++0x标准以前,为了弥补assert和#error的不足,出现了一些第三方解决方案,能够做编译期的静态检查,例如:BOOST_STATIC_ASSERT和LOKI_STATIC_CHECK,但因为它们都是利用了一些编译器的隐晦特性实现的trick,可移植性、简便性都不是太好,还会下降编译速度,并且功能也不够完善,例如BOOST_STATIC_ASSERT就不能定义错误提示文字,而LOKI_STATIC_CHECK则要求提示文字知足C++类型定义的语法。