8

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?

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • +1, but I still don't understand how the 1st version will emit the code ? Those are just empty `struct` declarations only right ? – iammilind Aug 05 '11 at 09:56
  • @iammilind: There's a temporary construction which might emit some code. – sharptooth Aug 05 '11 at 09:58
  • 1
    @sharptooth The type is an empty POD. I don’t see any scenario where the construction wouldn’t be elided. That said, your other point to prefer the second solution is valid. – Konrad Rudolph Aug 05 '11 at 10:00
  • @Konrad Rudolph: Yes, I know that in all sane compilers the optimizer will do its job, but that's not guaranteed. – sharptooth Aug 05 '11 at 10:02
  • 1
    Another reason to prefer one or the other could be how nice is the error generated in case of failure. I guess on most platforms the typedef solution will be better even in this respect. – Suma Aug 05 '11 at 10:05
  • 1
    It's not guaranteed that the typedef emits no code, either. For example, an implementation that instruments its code for profiling purposes is permitted to emit some code here that increments a record of the current source file line number. That would conform to the standard. If you're talking just about visual C++, then for each kind of assert you can check whether it emits code or not with the compiler options you're interested in, I doubt you'll see problems with any kind of optimization enabled. – Steve Jessop Aug 05 '11 at 10:20
  • In practice, `BOOST_STATIC_ASSERT` seems to use [`typedef`](http://www.boost.org/doc/libs/1_47_0/doc/html/boost_staticassert/how.html) [too](http://www.boost.org/doc/libs/1_47_0/boost/static_assert.hpp). – Ise Wisteria Aug 05 '11 at 11:15

2 Answers2

4

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.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 2
    There are simple ways of fixing this, though (and these are used in “real” implementations of the idiom) – for instance, append the `__LINE__` number to the typedef’d name: [ideone demo](http://www.ideone.com/655KW) – Konrad Rudolph Aug 05 '11 at 10:08
  • That's interesting - VC++ 9 compiles that no problem. – sharptooth Aug 05 '11 at 10:11
  • @iammilind To be honest, I don’t see the problem in practice. One line, one statement. It’s such a simple rule, there is *no reason* to violate it. – Konrad Rudolph Aug 05 '11 at 10:20
  • 1
    @sharptooth I believe VC++9 is correct. This should only fail when the typedefs are to different types, as far as I know. Which, in this case, can never happen unless an assertion is triggered anyway. – Konrad Rudolph Aug 05 '11 at 10:21
2

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.

James Kanze
  • 150,581
  • 18
  • 184
  • 329