Sunday, December 25, 2011

C++ tricks: compile time assert

Intro. I've been long thinking to start my own blog, at least a couple of years now. A common objection everyone always has is "OK, I feel enthusiastic right now. But can I keep up in the long-term?" The bad news is I still don't know the answer, though I'll do my best to allocate at least some time on it. But luckily this question does not stop me anymore. "If you feel like you'd love to write, right now, don't think, just write!" That's what I said to myself. And here it is: my first blog post! The topic I've chosen to discuss for the very first post is rather simple, yet nevertheless interesting: compile time assertion in C++.
Motivation: evaluate a static expression and make sure certain contract is always met.
First of all, one can add a runtime check of course. Second, it's better to document the restrictions anyway to avoid accidental bugs. But: explicit assert is better than implicit and the sooner the problem is found, the better. If we have a static expression, can't we use some magic to assert that at compilation? So that if for some reason the contract is not met, the compilation would fail and report exactly what happened. Yes, we can.
Solution: among plenty of features, C++11 finally comes along with a static assert and allows to use static_assert function like this:
And these solutions work just fine, supported by all major compilers. But I'd like to draw attention to the alternatives some of which I used long before C++0x and it's nice to know they exist.
Boost solution: BOOST_STATIC_ASSERT from Boost library solves the problem, though it has a limitation: one can't pass a human readable message to the compiler. And everyone knows compiler errors can be very cryptic.
When the assertion is false, the programmer would see "Illegal use of STATIC_ASSERTION_FAILURE <false>" error. OK, seems good enough, but what if one does not want a dependency on Boost?
Windows solution: Use C_ASSERT macro from Windows.h. A major drawback is quite obvious, this solution is platform dependent. But the implementation is so simple, let's try to port it and in addition make a couple of improvements.
Google solution. My favourite one. I call this a Google solution, because I learned it when I worked for Google back in 2006, though I'm pretty sure it was used even before that. Here's the code:
The compiler now triggers a "error: size of array ‘data_should_be_exactly_64_bytes’ is negative". It's still not ideal, but it points to the exact line of the assert, and provides at least some reason. Also note that under the hood the assert is just a typedef, so it's not compiled into assembly instructions and doesn't consume memory.
Real-life usages. Let's repeat that dedicated compiler support (static_assert is not even a macro, but a special directive) is always better and everyone is encouraged to use it now. Here are a few examples when it might be handy:





No comments:

Post a Comment