【问题标题】:BOOST_STATIC_ASSERT without boostBOOST_STATIC_ASSERT 没有升压
【发布时间】:2009-12-30 12:40:57
【问题描述】:

由于在我工作的公司中禁止使用 boost,因此我需要在纯 C++ 中实现其功能。我已经研究了提升源,但它们似乎太复杂而无法理解,至少对我来说是这样。我知道 C++0x 标准中有一个名为 static_assert() 的东西,但我不想使用任何 C++0x 功能。

【问题讨论】:

  • 您有没有问过为什么不允许您使用 boost?
  • 没有人煞费苦心地建立案例,以便律师团队批准其使用?
  • @Gregory Pakosz,他们说因为它太复杂了:)
  • 你可以使用某种编译器吗?因为它们也很复杂

标签: c++ boost replace static-assert


【解决方案1】:

另一个技巧(可以在 C 中使用)是在断言失败时尝试构建一个负大小的数组:

#define ASSERT(cond) int foo[(cond) ? 1 : -1]

作为奖励,您可以使用 typedef 代替对象,这样它就可以在更多的上下文中使用,并且在成功时不会发生:

#define ASSERT(cond) typedef int foo[(cond) ? 1 : -1]

最后,建立一个名称冲突可能性较小的名称(并且至少可以在不同的行中重复使用):

#define CAT_(a, b) a ## b
#define CAT(a, b) CAT_(a, b)
#define ASSERT(cond) typedef int CAT(AsSeRt, __LINE__)[(cond) ? 1 : -1]

【讨论】:

  • 有人能解释一下为什么需要两个 CAT 宏吗?你想避免什么问题?谢谢。
  • 如果你不这样做,宏参数(如__LINE__)不会被扩展。所以它会生成AsSeRt__LINE__ 而不是想要的AsSeRt42。我很确定某处有一个问题详细解释了这一点。
【解决方案2】:
template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};

int main() {
   StaticAssert< (4>3) >(); //OK
   StaticAssert< (2+2==5) >(); //ERROR
}

【讨论】:

  • +1 很简单,但我希望有一条与断言相关联的消息
  • @Gregory: StaticAssert&lt; (2+2==5) &gt; associatedMessage();
  • 有些地方你不想/不能使用变量
  • @Gregory: typedef StaticAssert&lt; (2+2==5) &gt; AssociatedMessage_t;
  • 前两行中的struct 关键字是不是漏掉了?并且typedef 技巧似乎不起作用 - 不完整的类型似乎是可以接受的(事实上,结构似乎甚至可以声明,例如一个负大小的数组但 typedefing 仍然可以编译,因为它没有实例化模板?)
【解决方案3】:

这是我自己的从我的代码库中提取的静态断言的实现:Pre-C++11 Static Assertions Without Boost

用法:

STATIC_ASSERT(expression, message);

当静态断言测试失败时,会生成一条包含STATIC_ASSERTION_FAILED_AT_LINE_xxx_message 的编译器错误消息。

message 必须是有效的 C++ 标识符,例如 no_you_cant_have_a_pony,它将产生一个编译器错误,其中包含:

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;
}

【讨论】:

  • 非常好!这是一个完整的解决方案(如果您想避免 boost 本身,也是 boost 实现的一个很好的替代方案)+1
  • 如果您有 -Wunused-local-typedef 和警告作为错误,这将无法构建,并出现有关未使用 typedef 的错误。这可以通过将__attribute__ ((unused)) 添加到STATIC_ASSERT 宏中的typedef 来规避(至少对于gcc 和clang)。
【解决方案4】:

您可以简单地将Boost source file 中的宏复制到您自己的代码中。如果您不需要支持 Boost 支持的所有编译器,您只需为您的编译器选择正确的定义并省略该文件中的其余 #ifdefs。

【讨论】:

  • 在 Boost 的许可下合法吗?
【解决方案5】:

我相信这应该可行:

template<bool> struct CompileTimeAssert;   
template<> struct CompileTimeAssert<true>{};
#define STATIC_ASSERT(e) (CompileTimeAssert <(e) != 0>())

【讨论】:

    【解决方案6】:

    我正在使用以下头文件,其中的代码是从别人那里抄来的......

    #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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-13
      • 2010-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多