2009-12-30 32 views
22

Kể từ khi tăng bị cấm trong một công ty tôi làm việc cho tôi cần phải thực hiện chức năng của nó trong C++ tinh khiết. Tôi đã xem xét các nguồn tăng nhưng dường như chúng quá phức tạp để hiểu, ít nhất là đối với tôi. Tôi biết có cái gì đó gọi là static_assert() trong standart C++ 0x, nhưng tôi không muốn sử dụng bất kỳ tính năng C++ 0x nào.BOOST_STATIC_ASSERT mà không cần tăng cường

+0

làm bạn hỏi tại sao bạn không được phép sử dụng tăng? –

+3

Không ai chịu nỗi đau khi xây dựng vụ án để nhóm luật sư chấp thuận việc sử dụng nó? – AProgrammer

+1

@Gregory Pakosz, họ nói bởi vì nó quá phức tạp :) – Konstantin

Trả lời

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

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

+1 đơn giản, nhưng tôi muốn có một thông báo liên quan đến xác nhận –

+0

@Gregory: 'StaticAssert < (2+2==5) > associatedMessage();' –

+1

có những nơi bạn không muốn/không thể sử dụng biến mặc dù –

3

Bạn chỉ cần sao chép macro từ Boost source file vào mã của riêng bạn. Nếu bạn không cần hỗ trợ tất cả các trình biên dịch, Boost hỗ trợ bạn có thể chọn đúng định nghĩa cho trình biên dịch của bạn và bỏ qua phần còn lại của tệp #ifdef trong tệp đó.

+2

Điều đó có hợp pháp với giấy phép của Boost không? – gatopeich

23

Một mẹo nhỏ khác (có thể được sử dụng trong C) là cố gắng xây dựng một mảng với kích thước tiêu cực nếu khẳng định thất bại:

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

như một phần thưởng, bạn có thể sử dụng một typedef thay vì một đối tượng, do đó nó là có thể sử dụng trong nhiều bối cảnh và không xảy ra khi nó thành công:

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

cuối cùng, xây dựng một tên có ít cơ hội của tên đụng độ (và tái sử dụng ít nhất là trong dòng khác nhau):

#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

Ai đó có thể giải thích tại sao hai macro CAT là cần thiết? Bạn đang cố tránh vấn đề gì? Cảm ơn. – grokus

+6

Nếu bạn không làm điều đó, các đối số là các macro (như '__LINE__') không được mở rộng. Vì vậy, nó sẽ tạo ra 'AsSeRt__LINE__' thay vì muốn 'AsSeRt42'. Tôi khá chắc chắn có một câu hỏi ở đâu đó giải thích chi tiết này. – AProgrammer

2

Tôi đang sử dụng tập tin tiêu đề sau đây, với mã tách từ người khác ...

#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

Đây là thực hiện riêng của tôi về khẳng định tĩnh chiết xuất từ ​​cơ sở mã của tôi: Pre-C++11 Static Assertions Without Boost.

Cách sử dụng:

STATIC_ASSERT(expression, message);

Khi thử nghiệm khẳng định tĩnh thất bại, một thông báo lỗi biên dịch rằng bằng cách nào đó có chứa các STATIC_ASSERTION_FAILED_AT_LINE_xxx_message được tạo ra.

message có phải là một C++ định danh hợp lệ, như no_you_cant_have_a_pony mà sẽ tạo ra một lỗi biên dịch có chứa:

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 cho "no_you_cant_have_a_pony" –

+2

Rất đẹp! Đây là một giải pháp hoàn chỉnh (và là một giải pháp thay thế tốt để tăng cường triển khai nếu bạn muốn tránh tăng cường chính nó) +1 – Samaursa

3

Tôi tin rằng điều này sẽ làm việc:

template<bool> struct CompileTimeAssert; 
template<> struct CompileTimeAssert<true>{}; 
#define STATIC_ASSERT(e) (CompileTimeAssert <(e) != 0>()) 
Các vấn đề liên quan