Since boost is forbidden in a company I work for I need to implement its functionality in pure C++. I've looked into boost sources but they seem to be too complex to understand, at least for me. I know there is something called static_assert() in the C++0x standart, but I'd like not to use any C++0x features.
- did you ask why you're not allowed to use boost?Gregory Pakosz– Gregory Pakosz2009-12-30 14:05:49 +00:00Commented Dec 30, 2009 at 14:05
- 3Nobody took the pain to build the case so that the lawyer's team give its approval for its use?AProgrammer– AProgrammer2009-12-30 14:24:44 +00:00Commented Dec 30, 2009 at 14:24
- 1@Gregory Pakosz, they say because it is too complex :)Konstantin– Konstantin2009-12-30 22:26:49 +00:00Commented Dec 30, 2009 at 22:26
- and can you use a compiler of some sort? because they are complex toograywolf– graywolf2016-01-27 16:33:26 +00:00Commented Jan 27, 2016 at 16:33
6 Answers
One other trick (which can be used in C) is to try to build an array with a negative size if the assert fail:
#define ASSERT(cond) int foo[(cond) ? 1 : -1] as a bonus, you may use a typedef instead of an object, so that it is usable in more contexts and doesn't takes place when it succeed:
#define ASSERT(cond) typedef int foo[(cond) ? 1 : -1] finally, build a name with less chance of name clash (and reusable at least in different lines):
#define CAT_(a, b) a ## b #define CAT(a, b) CAT_(a, b) #define ASSERT(cond) typedef int CAT(AsSeRt, __LINE__)[(cond) ? 1 : -1] 2 Comments
__LINE__) aren't expanded. So it would generate AsSeRt__LINE__ instead of the wanted AsSeRt42. I'm pretty sure there is a question somewhere explaining this in detail.template<bool> struct StaticAssert; template<> struct StaticAssert<true> {}; int main() { StaticAssert< (4>3) >(); //OK StaticAssert< (2+2==5) >(); //ERROR } 6 Comments
StaticAssert< (2+2==5) > associatedMessage();typedef StaticAssert< (2+2==5) > AssociatedMessage_t;struct keyword in the first two lines? And the typedef trick doesn't appear to work - incomplete types appear to be acceptable (in fact it seems the struct might even declare, e.g a negative-sized array but typedeffing would still compile, as it doesn't instantiate the template?)Here is my own implementation of static assertions extracted from my code base: Pre-C++11 Static Assertions Without Boost.
Usage:
STATIC_ASSERT(expression, message);
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, like no_you_cant_have_a_pony which will produce a compiler error containing:
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; } 2 Comments
-Wunused-local-typedef and warnings as errors, this will fail to build with an error about unused typedef. That can be circumvented by adding __attribute__ ((unused)) to the typedef in the STATIC_ASSERT macro (at least for gcc and clang).You could simply copy the macro from the Boost source file to your own code. If you don't need to support all the compilers Boost supports you can just pick the right definition for your compiler and omit the rest of the #ifdefs in that file.
1 Comment
I am using the following header file, with code ripped from someone else...
#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