C++除法運算 // 靜態斷言

weixin_30488085發表於2020-04-06

1、C++中"/"運算:對兩個整數做除法,結果仍為整數,如果它的商包含小數部分,則小樹部分會被截除。

     C++ Primer 第五章 P130

2、靜態斷言(static_assert)

簡介

C++0x中引入了static_assert這個關鍵字,用來做編譯期間的斷言,因此叫做靜態斷言。

其語法很簡單:static_assert(常量表示式,提示字串)。

如果第一個引數常量表示式的值為真(true或者非零值),那麼static_assert不做任何事情,就像它不存在一樣,否則會產生一條編譯錯誤,錯誤位置就是該static_assert語句所在行,錯誤提示就是第二個引數提示字串。

 

說明

使用static_assert,我們可以在編譯期間發現更多的錯誤,用編譯器來強制保證一些契約,並幫助我們改善編譯資訊的可讀性,尤其是用於模板的時候。

static_assert可以用在全域性作用域中,名稱空間中,類作用域中,函式作用域中,幾乎可以不受限制的使用。

編譯器在遇到一個static_assert語句時,通常立刻將其第一個引數作為常量表示式進行演算,但如果該常量表示式依賴於某些模板引數,則延遲到模板例項化時再進行演算,這就讓檢查模板引數成為了可能。

由於之前有望加入C++0x標準的concepts提案最終被否決了,因此對於檢查模板引數是否符合期望的重任,就要靠static_assert來完成了,所以如何構造適當的常量表示式,將是一個值得探討的話題。

效能方面,由於是static_assert編譯期間斷言,不生成目的碼,因此static_assert不會造成任何執行期效能損失。

 

範例

下面是一個來自MSDN的簡單範例:

static_assert(sizeof(void *) == 4, "64-bit code generation is not supported.");

static_assert用來確保編譯僅在32位的平臺上進行,不支援64位的平臺,該語句可以放在檔案的開頭處,這樣可以儘早檢查,以節省失敗情況下的編譯時間。

再看另一個範例:

 1: struct MyClass
   2: {
   3:     char m_value;
   4: };
   5:  
   6: struct MyEmptyClass
   7: {
   8:     void func();
   9: };
  10:  
  11: // 確保MyEmptyClass是一個空類(沒有任何非靜態成員變數,也沒有虛擬函式)
  12: static_assert(std::is_empty<MyEmptyClass>::value, "empty class needed");
  13:  
  14: //確保MyClass是一個非空類
  15: static_assert(!std::is_empty<MyClass>::value, "non-empty class needed");
  16:  
  17: template <typename T, typename U, typename V>
  18: class MyTemplate
  19: {
  20:     // 確保模板引數T是一個非空類
  21:     static_assert(
  22:         !std::is_empty<T>::value,
  23:         "T should be n non-empty class"
  24:         );
  25:  
  26:     // 確保模板引數U是一個空類
  27:     static_assert(
  28:         std::is_empty<U>::value,
  29:         "U should be an empty class"
  30:         );
  31:  
  32:     // 確保模板引數V是從std::allocator<T>直接或間接派生而來,
  33:     // 或者V就是std::allocator<T>
  34:     static_assert(
  35:         std::is_base_of<std::allocator<T>, V>::value,
  36:         "V should inherit from std::allocator<T>"
  37:         );
  38:  
  39: };
  40:  
  41: // 僅當模板例項化時,MyTemplate裡面的那三個static_assert才會真正被演算,
  42: // 藉此檢查模板引數是否符合期望
  43: template class MyTemplate<MyClass, MyEmptyClass, std::allocator<MyClass>>;

 

通過這個例子我們可以看出來,static_assert可以很靈活的使用,通過構造適當的常量表示式,我們可以檢查很多東西。比如範例中std::is_emptystd::is_base_of都是C++新的標準庫提供的type traits模板,我們使用這些模板可以檢查很多型別資訊。

 

相關比較

我們知道,C++現有的標準中,就有assert、#error兩個設施,也是用來檢查錯誤的,還有一些第三方的靜態斷言實現。

assert是執行期斷言,它用來發現執行期間的錯誤,不能提前到編譯期發現錯誤,也不具有強制性,也談不上改善編譯資訊的可讀性,既然是執行期檢查,對效能當然是有影響的,所以經常在發行版本中,assert都會被關掉;

#error可看做預編譯期斷言,甚至都算不上斷言,僅僅能在預編譯時顯示一個錯誤資訊,它能做的不多,可以參與預編譯的條件檢查,由於它無法獲得編譯資訊,當然就做不了更進一步分析了。

那麼,在stastic_assert提交到C++0x標準之前,為了彌補assert#error的不足,出現了一些第三方解決方案,可以作編譯期的靜態檢查,例如BOOST_STATIC_ASSERTLOKI_STATIC_CHECK,但由於它們都是利用了一些編譯器的隱晦特性實現的trick,可移植性、簡便性都不是太好,還會降低編譯速度,而且功能也不夠完善,例如BOOST_STATIC_ASSERT就不能定義錯誤提示文字,而LOKI_STATIC_CHECK則要求提示文字滿足C++型別定義的語法。

 

轉載於:https://www.cnblogs.com/rong86/p/3459267.html

相關文章