2009-12-30 41 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>())