Home > Articles > Programming > C/C++

C++ Reference Guide

Hosted by

Toggle Open Guide Table of ContentsGuide Contents

Close Table of ContentsGuide Contents

Close Table of Contents

Static Assertions

Last updated Jan 1, 2003.

C++09 introduces a new keyword, static_assert that operates more or less as the assert() macro except that it's evaluated at compile-time. Find out here what static_assert is used for and how it differs from concepts.

assert() And #error

C++03 already supports two facilities for testing software assertions:

  • assert()
  • #error

Neither of these is suitable for template programming. The assert() macro is evaluated at runtime, which is too late for examining a template specialization failure. By contrast, the #error preprocessor directive is evaluated during the preprocessing stage, which is too early for looking into template specializations.

C++ libraries that use templates extensively (is there any serious C++ library these days that doesn't?) need a mechanism for testing software assertions at compile-time. The solution is a new assertion facility that is evaluated when template specializations are processed. More specifically, the design requirements of the new assertion facilities are:

  • The assertion evaluation must be performed during compile time. No runtime cost or space overhead are acceptable.
  • The assertion facility must have simple and intuitive syntax.
  • An assertion failure must result in a meaningful and informative error message.
  • An assertion can be used at namespace, class, or block scope.

To meet all of these requirements and improve the detection of compile-time assertion failures, C++09 introduces a new keyword called static_assert. A static_assert declaration may appear anywhere a using-declaration is allowed. A static_assert declaration has the following form:

static_assert (integral-constant-expression, string-literal);

If the constant-expression in the static assertion evaluates as 0 (i.e., an assertion failure), the compiler will issue a diagnostic message containing the string literal provided as the second argument. Otherwise, the static_assert has no effect. A static_assert-declaration shall not declare a new type or object. It does not imply any size or time cost at runtime.

Scope

A static_assert declaration can appear at a namespace scope, block scope, and class member declaration lists. When used at a namespace scope, a static_assert declaration may replace the #error preprocessor directive. For example, the following static_assert declaration ensures that the implementation supports 64-bit addressing:

static_assert(sizeof(void*) >= 8, "64-bit addressing is required for this program");

A static_assert declaration at a class scope enables the implementer to enforce certain requirements on the said class. The following string template requires that the type CharT shall be a POD type:

template <class CharT, class Traits = std::char_traits<CharT> >
class basic_string 
{
 static_assert(tr1::is_pod<CharT>::value, "Argument CharT must be a POD type");
};

When the compiler creates an instance of basic_string<T> it checks whether the template argument is a POD type. If this isn't the case, compilation is aborted with the error message provided as the second argument.

Finally, a static_assert declaration may appear at a block scope. The main advantage of such static_assert declarations is that you can confine them to specific blocks in the program. Thus, a member function can use a local static assertion to enforce a certain requirement while the remaining member functions of the same class remain independent of that requirement. In the following example, the member function Client::func() uses static_assert to verify that the local type MemoryPage occupies the exact same size of a system virtual memory page:

#include "systempagesize.h"
class Client {
public:
 int func()
 {
  struct MemoryPage
 {
  //...
 };
  static_assert(sizeof(MemoryPage) == PAGESIZE,
     "MemoryPage must occupy exactly the same size of a system memory page");
   // ...
 }
    // ...
};

Concepts and static_assert

Seemingly, static_assert's roles resemble those of concepts. However, there is no overlap between the two. Concepts do not eliminate the need for static_assert because static_assert can be useful in programs that do not use templates (recall that concepts are used with templates exclusively). In addition, static_assert combined with type traits enable the implementer to diagnose errors that concepts cannot detect. Take for example the requirement that CharT shall be a POD type. Using constraints alone, it's difficult to express this constraint. Furthermore, in some cases, expressing requirements such as 64-bit addressing with static_assert seems more intuitive than writing a full-blown constraint.

Presently, several compilers implement static_assert including IBM, MetroWerks, Comeau and GCC 3.3