无效的静态断言行为

时间:2009-12-23 09:50:38

标签: c++ c gcc floating-point

我正在尝试使用GCC v4.3.x设置静态断言(在main函数之外):

#define STATIC_ASSERT(cond) extern void static_assert(int arg[(cond) ? 1 : -1])
STATIC_ASSERT( (double)1 == (double)1 ); // failed

但是当我使用浮点数时,断言总是失败。

是否可以正确运行此静态断言?​​

3 个答案:

答案 0 :(得分:9)

C ++ Standard 2003, 5.19“常量表达式”,第1段。

  

在一些地方,C ++需要   评估为的表达式   积分或枚举常数: as   数组边界(8.3.4,5.3.4),视情况而定   表达式(6.4.2),作为位字段   长度(9.6),作为调查员   初始化器(7.2),作为静态成员   初始化器(9.4.2),并作为整体   或枚举非类型模板   论证(14.3)。

     

常数表达式:   条件表达式

     

积分常量表达式可以   仅涉及文字(2.13),   枚举器,const变量或静态   积分或数据的成员   使用初始化的枚举类型   常量表达式(8.5),非类型   积分或积分的模板参数   枚举类型和sizeof   表达式。 浮动文字   (2.13.3)只有在出现时才会出现   强制转换为整数或枚举类型。   只输入转换为积分或   可以使用枚举类型。在   特别是,除了sizeof   表达式,函数,类对象,   指针或引用不得   使用,分配,增量,   递减,函数调用或逗号   不得使用运营商。

答案 1 :(得分:4)

我认为这与规则有关,即除了整数或枚举类型之外的任何东西都不能出现在常量表达式中。

// would all work for example
STATIC_ASSERT( 1.0 == 1.0 );
STATIC_ASSERT( (int)1.0 == (int)1.0 );

所以这不是断言本身无效,并导致编译错误,这是你的演员......

只是为了记录,当然,提升也有static assert

答案 2 :(得分:2)

编辑:

实际上,将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的数组停止编译。