Static assertions in C++

Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their way to become runtime problems are harder to detect and may go unchecked until such time that the code reaches a customer. The later the defect is identified the more costly it is in terms of time and money.

A static assertion is similar to a runtime assertion, in so far as it allows the programmer to assert that an expression must be true, or an error message must be raised. The difference is that static assertions are triggered at compile time rather than runtime. How is this useful? Well, how about a situation where we’ve had to make assumptions about the capacity of a specific type, say int?
The C++ Standard makes no specific claims about how big an int will be other than it “has the natural size suggested by the architecture of the execution environment.”

What does this actually mean? Well, in reality, it means the size of an int could be any size. The same is true of other types; a long must be as least as big as an int and an int at least s big as a short. Clearly, making an assumption about type size is non-portable and potentially dangerous, and should only be done in controlled cases, such as writing an OS kernel for a particular processor with a particular compiler. As soon as the programmer loses the ability to specify the compiler and the target architecture, type size assumptions go out the window. So, how does a static assertion help? Good question, let’s see…

Wouldn’t it be nice if we could assert our assumption about the size of a type at compile time so that if this assumption breaks, we are alerted immediately? For example, the code is built by a different compiler than the author used on a platform he did not anticipate. Enter static assertions. The trick is to turn to templates and, specifically, make use of the fact that a template variant, that is not instantiated, will not cause a compile time failure even if it contains erroneous code.

Create a template function that takes a bool template value parameter (not a function parameter). Within the function create a char array and use the value of the bool to determine the size. In the case where the bool template value is true, a char array of one element will be created. Since this will never be used the compiler should happily optimize this away. In the case where the bool template value is false, the compiler will try to generate a template function that creates a char array of zero elements. Since this is invalid C++, a compiler error will ensue.

We can now use a simple macro to facilitate the use of this template and then use a sizeof() to assert the sizes of the types we are assuming. Of course, any compile time constant can be asserted with a static assert, this is just one example of usage.

template
inline void STATIC_ASSERT_IMPL()
{
	// B will be true or false, which will implictly convert to 1 or 0
	char STATIC_ASSERT_FAILURE[B] = {0};
}

#define STATIC_ASSERT(B) STATIC_ASSERT_IMPL <b>()

int main()
{
	// On a Windows 32 bit platform with Visual Studio 2005 this will not fail
	STATIC_ASSERT(sizeof(int) == 4);

	// On a Windows 32 bit platform with Visual Studio 2005 this *will* fail
	STATIC_ASSERT(sizeof(int) == 3);
}

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s