2011-01-28 185 views
1

這是靜態斷言技巧的一部分。我無法理解非專業班是如何工作的。有人可以向我解釋嗎?這段代碼是什麼意思?

編輯:與宏全碼:(從http://www.skynet.ie/~caolan/Fragments/C++StaticAssert.html拍攝)

#ifndef STATICASSERT_HXX 
#define STATICASSERT_HXX 
/* 
Lifted direct from: 
Modern C++ Design: Generic Programming and Design Patterns Applied 
Section 2.1 
by Andrei Alexandrescu 
*/ 
namespace ww 
{ 
    template<bool> class compile_time_check 
    { 
    public: 
     compile_time_check(...) {} 
    }; 

    template<> class compile_time_check<false> 
    { 
    }; 
} 

    /* 
    Similiar to assert, StaticAssert is only in operation when NDEBUG is not 
    defined. It will test its first argument at compile time and on failure 
    report the error message of the second argument, which must be a valid c++ 
    classname. i.e. no spaces, punctuation or reserved keywords. 
    */ 
#ifndef NDEBUG 
# define StaticAssert(test, errormsg)       \ 
    do {              \ 
     struct ERROR_##errormsg {};        \ 
     typedef ww::compile_time_check< (test) != 0 > tmplimpl; \ 
     tmplimpl aTemp = tmplimpl(ERROR_##errormsg());   \ 
     sizeof(aTemp);           \ 
    } while (0) 
#else 
# define StaticAssert(test, errormsg)       \ 
    do {} while (0) 
#endif 

#endif 

回答

5

宏調用此代碼的方式與此類似:

compile_time_check<static expression> temp(Error_Some_Struct_here); 

因此,舉例來說,你可以做這樣的:

compile_time_check<sizeof(Foo) < sizeof(Bar)> temp(Error_Foo_must_be_smaller_than_Bar); 

sizeof(Foo)小於sizeof(Bar),模板將實例化的非專業化的版本:

template<bool> class compile_time_check 
{ 
public: 
    compile_time_check(...) {} //What is this? 
}; 

和代碼基本上是「編譯成」此類的instanciation:

compile_time_check temp(Error_Foo_must_be_smaller_than_Bar); 

其中,是空的,什麼都不做,編譯器可以去除死代碼。 Bam,沒有運行時開銷,完成。

如果,另一方面,sizeof(Foo)大於或等於sizeof(Bar),它將代替實例化的專業版本:

template<> class compile_time_check<false> 
{ 
}; 

,它會嘗試調用構造函數compile_time_check::compile_time_check(struct),但由於它不」它存在,它是一個編譯錯誤。這是你想要的,因爲靜態斷言只有在斷言是真的時才應該編譯。

的原因構造函數採取可變參數參數列表,我相信,兩方面:

  1. 爲了確保它不會調用默認的構造函數,它的特殊版本會有。它的可變參數使您可以將任何結構作爲錯誤「字符串」傳入。或者,這可能是模板化的,構造函數可能會將模板對象作爲參數。
  2. 因此可以傳入錯誤消息。當assert爲true時,這被忽略,沒有任何事情發生,編譯器優化器刪除代碼。但是,如果斷言是錯誤的,錯誤字符串應顯示在錯誤消息中。或許像constructor not found for compile_time_check::compile_time_check(ERROR_Assertion_error_blah())

的替代,模板免費的(我相信它經常用於C),靜態斷言我以前在什麼地方見過是這樣的:

#define compile_time_assert(pred) switch(0){case: 0: case pred:;} 

這工作,因爲如果pred是假的,代碼將最終爲switch(0){case: 0: case 0:;},並且具有相同常量的兩個外殼標籤是錯誤。 In depth explanation here

+0

@Dan:看我的編輯。爲什麼宏有一個`sizeof(aTemp);`行? – nakiya 2011-01-28 06:11:54

+0

@Dan實際上`compile_time_check :: compile_time_check()`會編譯,因爲默認的構造函數可用。這就是爲什麼具有looong名稱的結構正在被傳遞。 – ssmir 2011-01-28 06:16:06

3

擺脫了命名空間的時刻(因爲它基本上是無關緊要的),你有什麼是:

template<bool> class compile_time_check 
{ 
public: 
    compile_time_check(...) {} //What is this? 
}; 

這多少是一個類模板。它有一個類型爲bool的非類型模板參數和一個可變參數構造函數,所以它會接受任何參數。

template<> class compile_time_check<false> 
{ 
}; 

這是價值false前面的模板的一個特例。因此,當你實例化compile_time_check<false> checker;時,它會使用這個。這種專業化有一個默認的構造函數(這是從來沒有使用過),但沒有構造函數,它將接受一個參數。

這樣做的目的是,這是永遠只能從這裏使用:

typedef ww::compile_time_check< (test) != 0 > tmplimpl; \ 
    tmplimpl aTemp = tmplimpl(ERROR_##errormsg());   \ 
    sizeof(aTemp);           \ 

在這種情況下,我們實例化一個tmplimpl對象與構造函數的參數。如果模板參數爲true,那麼這將起作用,但如果模板參數爲false,則它將使用上面的只有默認ctor的專業化,而不是一個會接受參數的專業化 - 因此編譯器會打印出來一個錯誤消息說是這樣的:

error: no ctor found for compile_time_check<condition>("<error message>"); 

隨後sizeof(aTemp);有強迫該對象在編譯時要評估的,所以我們認爲這是一個編譯器錯誤消息,而不是鏈接錯誤說compile_time_check::compile_time_check<false>()是一個懸而未決外部。