2009-12-30 70 views
22

因爲在我工作的公司中禁止提升,所以我需要在純C++中實現它的功能。我已經研究過助推源,但他們似乎太複雜,至少對我來說是無法理解的。我知道在C++ 0x standart中有一個叫static_assert()的東西,但我不想使用任何C++ 0x功能。BOOST_STATIC_ASSERT沒有提升

+0

做你問爲什麼你不允許使用提升? – 2009-12-30 14:05:49

+1

@Gregory Pakosz,他們說,因爲它太複雜了:) – Konstantin 2009-12-30 22:26:49

回答

19
template<bool> struct StaticAssert; 
template<> struct StaticAssert<true> {}; 

int main() { 
    StaticAssert< (4>3) >(); //OK 
    StaticAssert< (2+2==5) >(); //ERROR 
} 
+0

+1夠簡單,但我喜歡有一個與斷言相關的消息 – 2009-12-30 14:07:16

+0

@Gregory:'StaticAssert < (2+2==5) > associatedMessage();' – 2009-12-30 17:19:01

+1

有些地方你不想/不能使用變量雖然 – 2009-12-30 19:34:52

3

你可以從Boost source file宏簡單地複製到自己的代碼。如果您不需要支持Boost支持的所有編譯器,您可以爲編譯器選擇正確的定義,並省略該文件中其餘的#ifdef

+2

這是合法的Boost的許可證嗎? – gatopeich 2011-06-07 17:41:05

23

其他一招(其可以在C中使用的)是試圖建立一個數組具有負的大小,如果斷言失敗:

#define ASSERT(cond) int foo[(cond) ? 1 : -1] 

作爲獎勵,你可以使用一個typedef,而不是一個對象,因此,它在多個環境可用,並沒有發生,當它成功:

#define ASSERT(cond) typedef int foo[(cond) ? 1 : -1] 

最後,建立一個名稱與名稱衝突的機會更少(和可重複使用至少在不同線路):

#define CAT_(a, b) a ## b 
#define CAT(a, b) CAT_(a, b) 
#define ASSERT(cond) typedef int CAT(AsSeRt, __LINE__)[(cond) ? 1 : -1] 
+1

有人可以解釋爲什麼兩個CAT宏是必要的嗎?你想避免什麼問題?謝謝。 – grokus 2010-12-16 20:24:50

+6

如果你不這樣做,宏的參數(如'__LINE__')不會被擴展。所以它會生成'AsSeRt__LINE__'而不是想要的'AsSeRt42'。我很確定有一個問題在某處詳細解釋了這一點。 – AProgrammer 2010-12-17 14:58:37

2

我使用下面的頭文件,用代碼從別人撕開......

#ifndef STATIC_ASSERT__H 
#define STATIC_ASSERT__H 

/* ripped from http://www.pixelbeat.org/programming/gcc/static_assert.html */ 

#define ASSERT_CONCAT_(a, b) a##b 
#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b) 
/* These can't be used after statements in c89. */ 
#ifdef __COUNTER__ 
    /* microsoft */ 
    #define STATIC_ASSERT(e) enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1/(!!(e)) } 
#else 
    /* This can't be used twice on the same line so ensure if using in headers 
    * that the headers are not included twice (by wrapping in #ifndef...#endif) 
    * Note it doesn't cause an issue when used on same line of separate modules 
    * compiled with gcc -combine -fwhole-program. */ 
    #define STATIC_ASSERT(e) enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) } 
#endif 

/* http://msdn.microsoft.com/en-us/library/ms679289(VS.85).aspx */ 
#ifndef C_ASSERT 
#define C_ASSERT(e) STATIC_ASSERT(e) 
#endif 

#endif 
16

這是我自己實現從我的代碼庫中提取靜態斷言的:Pre-C++11 Static Assertions Without Boost

用法:

STATIC_ASSERT(expression, message);

當靜態斷言測試失敗,則生成以某種方式包含STATIC_ASSERTION_FAILED_AT_LINE_xxx_message一個編譯器的錯誤消息。

message必須是一個有效的C++標識符,如no_you_cant_have_a_pony這將產生含有編譯器錯誤:

STATIC_ASSERTION_FAILED_AT_LINE_1337_no_you_cant_have_a_pony :)

#define CONCATENATE(arg1, arg2) CONCATENATE1(arg1, arg2) 
#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2) 
#define CONCATENATE2(arg1, arg2) arg1##arg2 

/** 
* Usage: 
* 
* <code>STATIC_ASSERT(expression, message)</code> 
* 
* When the static assertion test fails, a compiler error message that somehow 
* contains the "STATIC_ASSERTION_FAILED_AT_LINE_xxx_message" is generated. 
* 
* /!\ message has to be a valid C++ identifier, that is to say it must not 
* contain space characters, cannot start with a digit, etc. 
* 
* STATIC_ASSERT(true, this_message_will_never_be_displayed); 
*/ 

#define STATIC_ASSERT(expression, message)\ 
    struct CONCATENATE(__static_assertion_at_line_, __LINE__)\ 
    {\ 
    implementation::StaticAssertion<static_cast<bool>((expression))> CONCATENATE(CONCATENATE(CONCATENATE(STATIC_ASSERTION_FAILED_AT_LINE_, __LINE__), _), message);\ 
    };\ 
    typedef implementation::StaticAssertionTest<sizeof(CONCATENATE(__static_assertion_at_line_, __LINE__))> CONCATENATE(__static_assertion_test_at_line_, __LINE__) 

    // note that we wrap the non existing type inside a struct to avoid warning 
    // messages about unused variables when static assertions are used at function 
    // scope 
    // the use of sizeof makes sure the assertion error is not ignored by SFINAE 

namespace implementation { 

    template <bool> 
    struct StaticAssertion; 

    template <> 
    struct StaticAssertion<true> 
    { 
    }; // StaticAssertion<true> 

    template<int i> 
    struct StaticAssertionTest 
    { 
    }; // StaticAssertionTest<int> 

} // namespace implementation 


STATIC_ASSERT(true, ok); 
STATIC_ASSERT(false, ko); 

int main() 
{ 
    return 0; 
} 
+6

+1「no_you_cant_have_a_pony」 – 2009-12-31 02:45:49

+2

非常好!這是一個完整的解決方案(如果你想避免自我提升,那麼這是一個很好的替代方案)+1 – Samaursa 2013-03-09 20:40:21

3

我認爲這應該工作:

template<bool> struct CompileTimeAssert; 
template<> struct CompileTimeAssert<true>{}; 
#define STATIC_ASSERT(e) (CompileTimeAssert <(e) != 0>())