EDIT:
Действительно, перемещение STATIC_ASSERT
из main()
дает ошибку компилятора, поскольку приведение к типу, отличному от целочисленного или перечислимого, не может появиться в выражении-константе. Удаление приведений работает с GCC, но это не действительный ICE (как указано @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;
}
дает:
main.cpp: 4: ошибка: размер массива 'arg' отрицателен
Ссылка: ISO / IEC 14882 - 5.19 Выражения констант
целочисленное константное выражение может включать в себя только литералы (2.13), перечислители, const
переменные или static
члены-данные целочисленных типов или типов перечисления, инициализированные константными выражениями (8.5), не тип параметры шаблона целочисленного или перечислимого типов, а также размер выражений. Плавающие литералы (2.13.3) могут появляться, только если они приводятся к целочисленным или перечислимым типам. Можно использовать только преобразования типов в целочисленные или перечислимые типы. В частности, за исключением sizeof
выражения, функции, объекты класса, указатели или ссылки не должны использоваться, а операторы присваивания, приращения, уменьшения, вызова функции или запятой не должны использоваться.
EDIT2: для записи, вот моя собственная реализация статических утверждений, извлеченных из моей базы кода: 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;
}
При использовании STATIC_ASSERT((float) 1 == (float) 1, must_be_true);
выдает правильную ошибку:
main.cpp: 49: ошибка: приведение к типу, отличному от целочисленного или перечислимого, не может присутствовать в выражении-константе
Какой у вас вопрос?
#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;
}
Компиляция с помощью gcc 4.4.2 дает мне:
main.cpp: в функции int main ():
main.cpp: 6: ошибка: размер массива 'arg' отрицателен
Так что да, (float)1 != (float)1
оценивается как false
и заставляет ваш макрос STATIC_ASSERT
использовать массив размером -1
, который останавливает компиляцию.