Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BOOST_STATIC_ASSERT without boost

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.

like image 990
Konstantin Avatar asked Dec 30 '09 12:12

Konstantin


4 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]
like image 164
AProgrammer Avatar answered Nov 15 '22 06:11

AProgrammer


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

int main() {
   StaticAssert< (4>3) >(); //OK
   StaticAssert< (2+2==5) >(); //ERROR
}
like image 31
Alexey Malistov Avatar answered Nov 15 '22 07:11

Alexey Malistov


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;
}
like image 34
Gregory Pakosz Avatar answered Nov 15 '22 05:11

Gregory Pakosz


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.

like image 32
sth Avatar answered Nov 15 '22 06:11

sth