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++類型定義的語法。

相關文章
相關標籤/搜索