Click here to Skip to main content
15,887,596 members
Articles / Programming Languages / C++

Static assert in C++

Rate me:
Please Sign up or sign in to vote.
4.00/5 (2 votes)
5 Aug 2010BSD3 min read 29.4K   11   5
A static, or compile-time, assert for C++

Just a quick little note today, to clarify something I mentioned in passing the other day in Bounds, and staying within them. I said “I added a static assert to validate the template parameters at compile time”, and it’s probably worthwhile to spell out how that works for those who haven't seen it before.

As a rule, the earlier you find an error, the easier it is to identify and fix. The errors spotted by your compiler are, naturally, easier to fix than the errors exhibited by your program as it is running. A static assert helps by letting you sanity-check the code you write, and generating a compiler error if you write code that is syntactically correct, but logically incorrect.

For instance, the bounds class takes a lower and upper boundary as template parameters, and assumes them to be ordered. Say we didn't have a static assert, and used it to find out if a randomly generated world in a space game is suitable for colonization, and what animals can be introduced.

C++
typedef bounds<int, -5, -30> polarbear_temp;
...
// generating a randomworld and it's temperature
...
// Adding various animals
if (polarbear_temp::in_bounds(randomworld_temp))
...

This would lead to a universe completely devoid of polar bears (which I'm sure we all can agree would be a bad thing), because there is no temperature that can be both greater than -5 and less than -30.

Because the limits are known at compile time, it makes sense to check them at compile time, too.

There are a number of ways of writing a static assert, but in general they tend to rely on some syntactical trickery that makes the compiler complain if an expression evaluates to false, and generate no or little code at all if an expression evaluates to true. There are a couple of examples in C in Wikipedia, but curiously no specific C++ example.

I can't recall where I first saw an example of the implementation I used in the bounds class, but it’s a quite well known method, using the expression being evaluated as a template parameter.

C++
// Assertion type
template <bool b>
struct static_assert{};
// Specialisation with member function
template <>
struct static_assert<true>
{
  static void valid_expression() {};
};
...
// Usage - replace TEST with the static expression to evaluate
static_assert< TEST >::valid_expression();

The way this works is through template specialisation. If the template expression evaluates to true, there is a type static_assert<true> that has a static member function valid_expression(), so the code compiles tidily (and the function call is likely optimized away). If, on the other hand, the expression evaluates to false, the compiler can only find the generic static_assert<bool b> to use, and that type doesn’t have a valid_expression().

(The ‘trick’ here is to remember that even if they have the same name, static_assert<true> and static_assert<bool b> are completely different and unrelated types, since they have different template arguments.)

So, because compiler sees the static_assert<false> type as static_assert<bool b>, you’ll get a complaint along the lines of ‘valid_expression’ : is not a member of ‘static_assert<b>’, and the file and line where it’s been invoked.

As often as not, I tend to re-write these as private members of a class that need static data validation, because it lets me provide a custom error message. For instance, in bounds (abridged here):

C++
template <typename T,                           // data type
  T lower_,                                     // lower limit
  T upper_ >                                    // upper limit
struct bounds
{
private:
  // Validate ordering of template parameters at compile time
  template <bool b> struct bounds_validation{};
  template <> struct bounds_validation<true>
  { static void lower_larger_than_upper() {}; };
public:
  // Type name for templated type
  typedef T type;

  // Check if value is within bounds
  static bool in_bounds(const type& val)
  {
    bounds_validation<lower_ <= upper_>::lower_larger_than_upper();
    return L::less(lower_, val) && U::less(val, upper_);
  }
...

Here, the declaration bounds<int, 5, 1> would generate the compiler error ‘lower_larger_than_upper’ : is not a member of ‘bounds< T, lower_,upper_ >::bounds_validation<b>’, which expresses more clearly what the error is.

Update: I should mention that there is – of course – a BOOST_STATIC_ASSERT, and there will be a static_assert in C++ 0x.


Tagged: C++, template

License

This article, along with any associated source code and files, is licensed under The BSD License


Written By
Software Developer (Senior)
Sweden Sweden
Orjan has worked as a professional developer - in Sweden and England - since 1993, using a range of languages (C++, Pascal, Delphi, C, C#, Visual Basic, Python and assemblers), but tends to return to C++.

Comments and Discussions

 
Generalstatic_assert Pin
geoyar12-Aug-10 11:38
professionalgeoyar12-Aug-10 11:38 
GeneralRe: static_assert Pin
Orjan Westin18-Aug-10 1:38
professionalOrjan Westin18-Aug-10 1:38 
GeneralRe: static_assert Pin
geoyar18-Aug-10 7:14
professionalgeoyar18-Aug-10 7:14 
GeneralRe: static_assert Pin
Orjan Westin18-Aug-10 10:03
professionalOrjan Westin18-Aug-10 10:03 
GeneralRe: static_assert Pin
Yuval Nir11-Oct-10 1:00
Yuval Nir11-Oct-10 1:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.