EDIT:
Indeed, moving STATIC_ASSERT
out of main()
gives a compiler error because a cast to a type other than an integral or enumeration type cannot appear in a constant-expression. Removing the casts works with GCC still it's not a valid ICE (as pointed by @AndreyT).
#define STATIC_ASSERT(cond) extern void static_assert(int arg[(cond) ? 1 : -1])
STATIC_ASSERT( 1.0 == 1.0 );
STATIC_ASSERT( 1.0 != 1.0 ); // this is line 4
int main()
{
return 0;
}
gives:
main.cpp:4: error: size of array ‘arg’ is negative
Reference: ISO/IEC 14882 - 5.19 Constant Expressions
An integral constant-expression can involve only literals (2.13), enumerators, const
variables or static
data members of integral or enumeration types initialized with constant expressions (8.5), non-type template parameters of integral or enumeration types, andsizeofexpressions. Floating literals (2.13.3) can appear only if they are cast to integral or enumeration types. Only type conversions to integral or enumeration types can be used. In particular, except in sizeof
expressions, functions, class objects, pointers, or references shall not be used, and assignment, increment, decrement, function-call, or comma operators shall not be used.
EDIT2: for the record, here is my own implementation of static assertions extracted from my code base: 1951741.cpp
#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(1.0f == 1.0 , ok);
STATIC_ASSERT(1.0f != 1.0 , ko);
int main()
{
return 0;
}
When using STATIC_ASSERT((float) 1 == (float) 1, must_be_true);
it gives a proper error:
main.cpp:49: error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression
What is your question exactly?
#define STATIC_ASSERT(cond) extern void static_assert(int arg[(cond) ? 1 : -1])
int main()
{
STATIC_ASSERT( (float)1 == (float)1 );
STATIC_ASSERT( (float)1 != (float)1 ); // this is line 6
return 0;
}
Compiling it with gcc 4.4.2 gives me:
main.cpp: In function ‘int main()’:
main.cpp:6: error: size of array ‘arg’ is negative
So yes, (float)1 != (float)1
evaluates to false
and makes your STATIC_ASSERT
macro use an array of size -1
which stops compilation.