为什么更喜欢基于typedef的静态断言的基于模板的静态断言?

时间:2011-08-05 09:37:12

标签: c++ templates visual-c++ static-assert

对于没有内置static_assert的C ++版本,有两个widely used静态断言实现。

第一个用于Boost并使用a template and a specialization of that template

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

一旦检查的条件为false,编译器就无法找到模板的通用版本,编译失败。

第二个使用typedef

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

一旦违反了检查条件,编译器会尝试typedef一个大小为-1的数组,这是非法的,因此是编译时错误。

对我来说后者更好,因为它保证不会发出任何代码,也可以这样使用(来自here):

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

而前者不能那样使用。

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

2 个答案:

答案 0 :(得分:4)

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

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

Demo

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

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

同样会出现对象构造正常的情况,但放置typedef语法不合适。所以那些都会落到同一个地方。

答案 1 :(得分:2)

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