Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why prefer template-based static assert over typedef-based static assert?

There're two widely used implementations of static assert for versions of C++ that don't have built-in static_assert.

The first one is used in Boost and uses 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)>()

Here once a condition to check is false the compiler is unable to find a generic version of template and compilation fails.

the second uses a typedef:

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

Here once a condition to check is violated the compiler attempts to typedef an array of size -1 and that's illegal hence a compile-time error.

To me the latter is better since it is guaranteed to emit no code and also it can be used like this (from 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

while the former can't be used like that.

Is there any reason to prefer the former implementation of static assert over the latter one?

like image 233
sharptooth Avatar asked Aug 05 '11 09:08

sharptooth


2 Answers

Second version of STATIC_ASSERT you cannot use one after another in the same block.

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

Demo.

On the other hand, in the example you posted, you cannot use first version (because it deals with temporary constructions). So both the version has their own audience. 1st version I can say is kind of mix of compile and runtime. However 2nd version is purely compile time.

Edit: sometimes for readability you may want to put all asserts in single line with comman operator (where only last instruction will effective in this case). I know that they can be put with ; too. But just for sake of having an example, this is one use case.

Similarly there will be situations where object construction will be ok but putting a typedef will not be ok syntactically. So all those will fall into same place.

like image 192
iammilind Avatar answered Nov 14 '22 14:11

iammilind


I've generally used the second, or some variant of it, in my own code. In practice, the Boost variant has the advantage that it can be used anywhere an expression may appear, and not just at statement level. It has the disadvantage that it can only be used where an expression may appear, and thus not at namespace scope.

like image 2
James Kanze Avatar answered Nov 14 '22 14:11

James Kanze