免费高清特黄a大片,九一h片在线免费看,a免费国产一级特黄aa大,国产精品国产主播在线观看,成人精品一区久久久久,一级特黄aa大片,俄罗斯无遮挡一级毛片

分享

C++11 靜態(tài)斷言(static

 xiejblan 2019-04-30

簡(jiǎn)介

C++0x中引入了static_assert這個(gè)關(guān)鍵字,用來(lái)做編譯期間的斷言,因此叫做靜態(tài)斷言。

其語(yǔ)法很簡(jiǎn)單:static_assert(常量表達(dá)式,提示字符串)。

如果第一個(gè)參數(shù)常量表達(dá)式的值為真(true或者非零值),那么static_assert不做任何事情,就像它不存在一樣,否則會(huì)產(chǎn)生一條編譯錯(cuò)誤,錯(cuò)誤位置就是該static_assert語(yǔ)句所在行,錯(cuò)誤提示就是第二個(gè)參數(shù)提示字符串。

 

說(shuō)明

使用static_assert,我們可以在編譯期間發(fā)現(xiàn)更多的錯(cuò)誤,用編譯器來(lái)強(qiáng)制保證一些契約,并幫助我們改善編譯信息的可讀性,尤其是用于模板的時(shí)候。

static_assert可以用在全局作用域中,命名空間中,類(lèi)作用域中,函數(shù)作用域中,幾乎可以不受限制的使用。

編譯器在遇到一個(gè)static_assert語(yǔ)句時(shí),通常立刻將其第一個(gè)參數(shù)作為常量表達(dá)式進(jìn)行演算,但如果該常量表達(dá)式依賴(lài)于某些模板參數(shù),則延遲到模板實(shí)例化時(shí)再進(jìn)行演算,這就讓檢查模板參數(shù)成為了可能。

由于之前有望加入C++0x標(biāo)準(zhǔn)的concepts提案最終被否決了,因此對(duì)于檢查模板參數(shù)是否符合期望的重任,就要靠static_assert來(lái)完成了,所以如何構(gòu)造適當(dāng)?shù)某A勘磉_(dá)式,將是一個(gè)值得探討的話題。

性能方面,由于是static_assert編譯期間斷言,不生成目標(biāo)代碼,因此static_assert不會(huì)造成任何運(yùn)行期性能損失。

 

范例

下面是一個(gè)來(lái)自MSDN的簡(jiǎn)單范例:

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

static_assert用來(lái)確保編譯僅在32位的平臺(tái)上進(jìn)行,不支持64位的平臺(tái),該語(yǔ)句可以放在文件的開(kāi)頭處,這樣可以盡早檢查,以節(jié)省失敗情況下的編譯時(shí)間。

再看另一個(gè)范例:

   1: struct MyClass
   2: {
   3:     char m_value;
   4: };
   5:  
   6: struct MyEmptyClass
   7: {
   8:     void func();
   9: };
  10:  
  11: // 確保MyEmptyClass是一個(gè)空類(lèi)(沒(méi)有任何非靜態(tài)成員變量,也沒(méi)有虛函數(shù))
  12: static_assert(std::is_empty<MyEmptyClass>::value, "empty class needed");
  13:  
  14: //確保MyClass是一個(gè)非空類(lèi)
  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:     // 確保模板參數(shù)T是一個(gè)非空類(lèi)
  21:     static_assert(
  22:         !std::is_empty<T>::value,
  23:         "T should be n non-empty class"
  24:         );
  25:  
  26:     // 確保模板參數(shù)U是一個(gè)空類(lèi)
  27:     static_assert(
  28:         std::is_empty<U>::value,
  29:         "U should be an empty class"
  30:         );
  31:  
  32:     // 確保模板參數(shù)V是從std::allocator<T>直接或間接派生而來(lái),
  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: // 僅當(dāng)模板實(shí)例化時(shí),MyTemplate里面的那三個(gè)static_assert才會(huì)真正被演算,
  42: // 藉此檢查模板參數(shù)是否符合期望
  43: template class MyTemplate<MyClass, MyEmptyClass, std::allocator<MyClass>>;
通過(guò)這個(gè)例子我們可以看出來(lái),static_assert可以很靈活的使用,通過(guò)構(gòu)造適當(dāng)?shù)某A勘磉_(dá)式,我們可以檢查很多東西。比如范例中std::is_emptystd::is_base_of都是C++新的標(biāo)準(zhǔn)庫(kù)提供的type traits模板,我們使用這些模板可以檢查很多類(lèi)型信息。

 

相關(guān)比較

我們知道,C++現(xiàn)有的標(biāo)準(zhǔn)中,就有assert、#error兩個(gè)設(shè)施,也是用來(lái)檢查錯(cuò)誤的,還有一些第三方的靜態(tài)斷言實(shí)現(xiàn)。

assert是運(yùn)行期斷言,它用來(lái)發(fā)現(xiàn)運(yùn)行期間的錯(cuò)誤,不能提前到編譯期發(fā)現(xiàn)錯(cuò)誤,也不具有強(qiáng)制性,也談不上改善編譯信息的可讀性,既然是運(yùn)行期檢查,對(duì)性能當(dāng)然是有影響的,所以經(jīng)常在發(fā)行版本中,assert都會(huì)被關(guān)掉;

#error可看做預(yù)編譯期斷言,甚至都算不上斷言,僅僅能在預(yù)編譯時(shí)顯示一個(gè)錯(cuò)誤信息,它能做的不多,可以參與預(yù)編譯的條件檢查,由于它無(wú)法獲得編譯信息,當(dāng)然就做不了更進(jìn)一步分析了。

那么,在stastic_assert提交到C++0x標(biāo)準(zhǔn)之前,為了彌補(bǔ)assert#error的不足,出現(xiàn)了一些第三方解決方案,可以作編譯期的靜態(tài)檢查,例如BOOST_STATIC_ASSERTLOKI_STATIC_CHECK,但由于它們都是利用了一些編譯器的隱晦特性實(shí)現(xiàn)的trick,可移植性、簡(jiǎn)便性都不是太好,還會(huì)降低編譯速度,而且功能也不夠完善,例如BOOST_STATIC_ASSERT就不能定義錯(cuò)誤提示文字,而LOKI_STATIC_CHECK則要求提示文字滿足C++類(lèi)型定義的語(yǔ)法。

 

譯器實(shí)現(xiàn)

gcc和vc的實(shí)現(xiàn)沒(méi)有太大的差別,均不支持中文提示,非常遺憾,而且VC僅支持ASCII編碼,L前綴就會(huì)編譯出錯(cuò)。GCC好像可以支持其他編碼,例如L前綴和U前綴,但我試過(guò)發(fā)現(xiàn)結(jié)果和ASCII編碼一樣。

static_assert的錯(cuò)誤提示,VC比GCC稍微友好一些,VC對(duì)上下文和調(diào)用堆棧都有較清晰描述,相比之下,GCC的提示簡(jiǎn)陋一些,但也算比較明確吧,本來(lái)么,static_assert很大程度上就是為了編譯器的提示信息更加友好而存在的。

 

應(yīng)用研究

最后再舉個(gè)例子,用來(lái)判斷某個(gè)類(lèi)是否有某個(gè)指定名字的成員,供參考和體驗(yàn)。其實(shí)static_assert的應(yīng)該很大程度上就是看如何構(gòu)造常量表達(dá)式了,這個(gè)例子中使用了decltype關(guān)鍵字(也是C++0x新特性)和SFINAE技巧,以及一些編譯器相關(guān)的技巧(主要是解決VC編譯器的bug),具體的技術(shù)細(xì)節(jié)和原理在今后的文章中還會(huì)仔細(xì)探討。

   1: // 判斷類(lèi)是否含有foo這個(gè)成員變量和成員函數(shù)
   2: // 針對(duì)GCC的實(shí)現(xiàn),基本上就是針對(duì)標(biāo)準(zhǔn)C++的實(shí)現(xiàn)
   3: #ifdef __GNUC__
   4:  
   5: // check_property_foo函數(shù)的兩個(gè)重載版本,結(jié)合decltype,
   6: // 通過(guò)SFINAE在編譯期推導(dǎo)指定類(lèi)型是否含有foo這個(gè)成員變量
   7: char check_property_foo(...);
   8:  
   9: template <typename T>
  10: void* check_property_foo(T const& t, decltype(&(t.foo)) p = 0);
  11:  
  12: // 這個(gè)類(lèi)模板通過(guò)check_property_foo得出T是否含有foo這個(gè)成員變量
  13: template <typename T>
  14: struct has_property_foo : public std::integral_constant<
  15:     bool, sizeof(check_property_foo(*static_cast(0))) == sizeof(void*)>
  16: {
  17: };
  18:  
  19: // check_method_foo函數(shù)的兩個(gè)重載版本,結(jié)合decltype,
  20: // 通過(guò)SFINAE在編譯期推導(dǎo)指定類(lèi)型是否含有foo這個(gè)成員函數(shù)
  21: char check_method_foo(...);
  22:  
  23: template <typename T>
  24: void* check_method_foo(T const& t, decltype(&(T::foo)) p = 0);
  25:  
  26: // 這個(gè)類(lèi)模板通過(guò)check_method_foo得出T是否含有foo這個(gè)成員函數(shù)
  27: template <typename T>
  28: struct has_method_foo  : public std::integral_constant<
  29:     bool, !has_property_foo::value &&
  30:     sizeof(check_method_foo(*static_cast(0))) == sizeof(void*)>
  31: {
  32: };
  33: #endif
  34:  
  35: // 針對(duì)VC的實(shí)現(xiàn),由于VC編譯器在處理decltype和SFINAE情況下存在bug,
  36: // 我們只能采用一些花招來(lái)繞過(guò)這個(gè)bug
  37: #ifdef _MSC_VER
  38:  
  39: // check_member_foo函數(shù)的兩個(gè)重載版本,結(jié)合decltype,
  40: // 通過(guò)SFINAE在編譯期推導(dǎo)指定類(lèi)型是否含有foo這個(gè)成員變量或函數(shù)
  41: char check_member_foo(...);
  42: 
  43: template <typename T>
  44: auto check_member_foo(T const& t, decltype(&(t.foo)) p = 0)->decltype(p);
  45:  
  46: // 這個(gè)類(lèi)模板通過(guò)check_member_foo得出T是否含有foo這個(gè)成員變量
  47: template <typename T>
  48: struct has_property_foo
  49: {
  50:     static const bool value =
  51:         sizeof(check_member_foo(*static_cast(0))) != sizeof(char) &&
  52:         std::is_pointerstatic_cast(0)))>::value;
  53: };
  54:
55: // 這個(gè)類(lèi)模板通過(guò)check_member_foo得出T是否含有foo這個(gè)成員函數(shù)
  56: template <typename T>
  57: struct has_method_foo
  58: {
  59:     static const bool value =
  60:         sizeof(check_member_foo(*static_cast(0))) != sizeof(char) &&
  61:         !std::is_pointerstatic_cast(0)))>::value;
  62: };
  63:  
  64: #endif
  65:  
  66: // 先定義幾個(gè)類(lèi)供實(shí)現(xiàn)檢測(cè)
  67: struct WithPropertyFoo
  68: {
  69:     int foo;
  70: };
  71:  
  72: struct WithMethodFoo
  73: {
  74:     void foo();
  75: };
  76:  
  77: struct WithRefPorpertyFoo
  78: {
  79:     int& foo;
  80: };
  81:  
  82: struct WithoutFoo
  83: {
  84:     void bar();
  85: };
  86:  
  87: // 用static_assert對(duì)這些條件進(jìn)行檢查
  88: static_assert(has_property_foo::value, "property foo needed");
  89: static_assert(has_method_foo::value, "method foo needed");
  90: static_assert(!has_property_foo::value, "no property foo");
  91: static_assert(!has_method_foo::value, "no methoed foo");
  92: static_assert(has_property_foo::value, "property foo needed");
  93: static_assert(!has_method_foo::value, "no method foo");

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多