8

对于没有内置的 C++ 版本,有两种广泛使用static_assert的静态断言实现。

第一个用于 Boost 并使用模板和该模板的特化

template <bool> struct static_assert;
template <> struct static_assert<true> {}; // only true is defined
#define  STATIC_ASSERT(x) static_assert<(x)>()

在这里,一旦要检查的条件为假,编译器就无法找到模板的通用版本并且编译失败。

第二个使用 a typedef

#define STATIC_ASSERT( x ) typedef char __STATIC_ASSERT__[( x )?1:-1]

在这里,一旦违反了要检查的条件,编译器就会尝试typedef使用大小为 -1 的数组,这是非法的,因此会出现编译时错误。

对我来说,后者更好,因为它保证不发出任何代码,而且它可以像这样使用(从这里):

template<int Shift> class BinaryFlag {
    STATIC_ASSERT( 0 <= Shift && Shift < sizeof( DWORD) * CHAR_BIT );
    public:
    static const DWORD FlagValue = static_cast<DWORD>( 1 << Shift );
};
#define BINARY_FLAG( n ) CBinaryFlag<n>::FlagValue

而前者不能那样使用。

有什么理由更喜欢静态断言的前一个实现而不是后一个?

4

2 回答 2

4

第二个版本的STATIC_ASSERT你不能在同一个区块里一个接一个地使用。

template<int N, int M>
void foo ()
{
  STATIC_ASSERT(N<M), STATIC_ASSERT(M<0);  // error
};

演示

另一方面,在您发布的示例中,您不能使用第一个版本(因为它处理临时结构)。所以这两个版本都有自己的受众。我可以说第一个版本是编译和运行时的混合。然而,第二个版本纯粹是编译时间。

编辑:有时为了可读性,您可能希望将所有断言与命令运算符放在一行中(在这种情况下,只有最后一条指令有效)。我知道它们也可以放在一起;。但只是为了举例,这是一个用例。

类似地,在某些情况下对象构造可以,但在typedef语法上放置 a 就不行。所以所有这些都会落到同一个地方。

于 2011-08-05T10:06:13.617 回答
2

我通常在我自己的代码中使用第二个或它的一些变体。在实践中,Boost 变体的优势在于它可以在任何可能出现表达式的地方使用,而不仅仅是在语句级别。它的缺点是只能在可能出现表达式的地方使用,因此不能在命名空间范围内使用。

于 2011-08-05T10:09:33.380 回答