C++11 static_assert

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;
}

 

和Assert,#error比较

咱们知道,C++现有的标准中,就有assert、#error两个设施,也是用来检查错误的,还有一些第三方的静态断言实现。

assert是运行期断言,它用来发现运行期间的错误,不能提早到编译期发现错误,也不具备强制性,也谈不上改善编译信息的可读性,既然是运行期检查,对性能固然是有影响的,因此常常在发行版本中,assert都会被关掉;

#error可看作预编译期断言,甚至都算不上断言,仅仅能在预编译时显示一个错误信息,它能作的很少,能够配合#ifdef/ifndef参与预编译的条件检查,因为它没法得到编译信息,固然就作不了更进一步分析了。

stastic_assert提交到C++0x标准以前,为了弥补assert#error的不足,出现了一些第三方解决方案,能够做编译期的静态检查,例如:BOOST_STATIC_ASSERTLOKI_STATIC_CHECK,但因为它们都是利用了一些编译器的隐晦特性实现的trick,可移植性、简便性都不是太好,还会下降编译速度,并且功能也不够完善,例如BOOST_STATIC_ASSERT就不能定义错误提示文字,而LOKI_STATIC_CHECK则要求提示文字知足C++类型定义的语法。

相关文章
相关标签/搜索