| 1 | [library Boost.StaticAssert |
|---|
| 2 | [copyright 2000 2005 Steve Cleary and John Maddock] |
|---|
| 3 | [purpose Compile time diagnostics library] |
|---|
| 4 | [license |
|---|
| 5 | Distributed under the Boost Software License, Version 1.0. |
|---|
| 6 | (See accompanying file LICENSE_1_0.txt or copy at |
|---|
| 7 | <ulink url="http://www.boost.org/LICENSE_1_0.txt"> |
|---|
| 8 | http://www.boost.org/LICENSE_1_0.txt |
|---|
| 9 | </ulink>) |
|---|
| 10 | ] |
|---|
| 11 | [authors [Maddock, John], [Cleary, Steve]] |
|---|
| 12 | [category template] |
|---|
| 13 | [category testing] |
|---|
| 14 | [category generic] |
|---|
| 15 | [last-revision $Date: 2007/05/09 17:20:56 $] |
|---|
| 16 | ] |
|---|
| 17 | |
|---|
| 18 | [section:intro Overview and Tutorial] |
|---|
| 19 | |
|---|
| 20 | This documentation is |
|---|
| 21 | [@http://boost-consulting.com/vault/index.php?action=downloadfile&filename=boost_static_assert-1.34.pdf&directory=PDF%20Documentation& |
|---|
| 22 | also available in printer-friendly PDF format]. |
|---|
| 23 | |
|---|
| 24 | The header `<boost/static_assert.hpp>` supplies a single macro `BOOST_STATIC_ASSERT(x)`, |
|---|
| 25 | which generates a compile time error message if the integral-constant-expression `x` |
|---|
| 26 | is not true. In other words it is the compile time equivalent of the assert macro; |
|---|
| 27 | this is sometimes known as a "compile-time-assertion", but will be called a |
|---|
| 28 | "static assertion" throughout these docs. Note that if the condition is `true`, |
|---|
| 29 | then the macro will generate neither code nor data - and the macro can also |
|---|
| 30 | be used at either namespace, class or function scope. When used in a template, |
|---|
| 31 | the static assertion will be evaluated at the time the template is instantiated; |
|---|
| 32 | this is particularly useful for validating template parameters. |
|---|
| 33 | |
|---|
| 34 | One of the aims of `BOOST_STATIC_ASSERT` is to generate readable error messages. |
|---|
| 35 | These immediately tell the user that a library is being used in a manner that |
|---|
| 36 | is not supported. While error messages obviously differ from compiler to compiler, |
|---|
| 37 | but you should see something like: |
|---|
| 38 | |
|---|
| 39 | Illegal use of STATIC_ASSERTION_FAILURE<false> |
|---|
| 40 | |
|---|
| 41 | Which is intended to at least catch the eye! |
|---|
| 42 | |
|---|
| 43 | You can use `BOOST_STATIC_ASSERT` at any place where you can place a declaration, |
|---|
| 44 | that is at class, function or namespace scope, this is illustrated by the |
|---|
| 45 | following examples: |
|---|
| 46 | |
|---|
| 47 | [section:namespace Use at namespace scope.] |
|---|
| 48 | |
|---|
| 49 | The macro can be used at namespace scope, if there is some requirement must |
|---|
| 50 | always be true; generally this means some platform specific requirement. |
|---|
| 51 | Suppose we require that `int` be at least a 32-bit integral type, and that `wchar_t` |
|---|
| 52 | be an unsigned type. We can verify this at compile time as follows: |
|---|
| 53 | |
|---|
| 54 | #include <climits> |
|---|
| 55 | #include <cwchar> |
|---|
| 56 | #include <limits> |
|---|
| 57 | #include <boost/static_assert.hpp> |
|---|
| 58 | |
|---|
| 59 | namespace my_conditions { |
|---|
| 60 | |
|---|
| 61 | BOOST_STATIC_ASSERT(std::numeric_limits<int>::digits >= 32); |
|---|
| 62 | BOOST_STATIC_ASSERT(WCHAR_MIN >= 0); |
|---|
| 63 | |
|---|
| 64 | } // namespace my_conditions |
|---|
| 65 | |
|---|
| 66 | The use of the namespace my_conditions here requires some comment. |
|---|
| 67 | The macro `BOOST_STATIC_ASSERT` works by generating an typedef declaration, |
|---|
| 68 | and since the typedef must have a name, the macro generates one automatically by |
|---|
| 69 | mangling a stub name with the value of `__LINE__`. When `BOOST_STATIC_ASSERT` is |
|---|
| 70 | used at either class or function scope then each use of `BOOST_STATIC_ASSERT` |
|---|
| 71 | is guaranteed to produce a name unique to that scope (provided you only use |
|---|
| 72 | the macro once on each line). However when used in a header at namespace |
|---|
| 73 | scope, that namespace can be continued over multiple headers, each of which |
|---|
| 74 | may have their own static assertions, and on the "same" lines, thereby generating |
|---|
| 75 | duplicate declarations. In theory the compiler should silently ignore duplicate |
|---|
| 76 | typedef declarations, however many do not do so (and even if they do they are |
|---|
| 77 | entitled to emit warnings in such cases). To avoid potential problems, if you |
|---|
| 78 | use `BOOST_STATIC_ASSERT` in a header and at namespace scope, then enclose |
|---|
| 79 | them in a namespace unique to that header. |
|---|
| 80 | |
|---|
| 81 | [endsect] |
|---|
| 82 | |
|---|
| 83 | [section:function Use at function scope] |
|---|
| 84 | |
|---|
| 85 | The macro is typically used at function scope inside template functions, |
|---|
| 86 | when the template arguments need checking. Imagine that we have an |
|---|
| 87 | iterator-based algorithm that requires random access iterators. |
|---|
| 88 | If the algorithm is instantiated with iterators that do not meet our |
|---|
| 89 | requirements then an error will be generated eventually, but this may |
|---|
| 90 | be nested deep inside several templates, making it hard for the user to |
|---|
| 91 | determine what went wrong. One option is to add a static assertion at |
|---|
| 92 | the top level of the template, in that case if the condition is not met, |
|---|
| 93 | then an error will be generated in a way that makes it reasonably obvious to |
|---|
| 94 | the user that the template is being misused. |
|---|
| 95 | |
|---|
| 96 | #include <iterator> |
|---|
| 97 | #include <boost/static_assert.hpp> |
|---|
| 98 | #include <boost/type_traits.hpp> |
|---|
| 99 | |
|---|
| 100 | template <class RandomAccessIterator > |
|---|
| 101 | RandomAccessIterator foo(RandomAccessIterator from, RandomAccessIterator to) |
|---|
| 102 | { |
|---|
| 103 | // this template can only be used with |
|---|
| 104 | // random access iterators... |
|---|
| 105 | typedef typename std::iterator_traits< RandomAccessIterator >::iterator_category cat; |
|---|
| 106 | BOOST_STATIC_ASSERT((boost::is_convertible<cat, const std::random_access_iterator_tag&>::value)); |
|---|
| 107 | // |
|---|
| 108 | // detail goes here... |
|---|
| 109 | return from; |
|---|
| 110 | } |
|---|
| 111 | |
|---|
| 112 | A couple of footnotes are in order here: the extra set of parenthesis around the |
|---|
| 113 | assert, is to prevent the comma inside the `is_convertible` template being |
|---|
| 114 | interpreted by the preprocessor as a macro argument separator; the target type |
|---|
| 115 | for `is_convertible` is a reference type, as some compilers have problems |
|---|
| 116 | using `is_convertible` when the conversion is via a user defined constructor |
|---|
| 117 | (in any case there is no guarantee that the iterator tag classes are |
|---|
| 118 | copy-constructible). |
|---|
| 119 | |
|---|
| 120 | [endsect] |
|---|
| 121 | |
|---|
| 122 | [section:class Use at class scope] |
|---|
| 123 | |
|---|
| 124 | The macro is typically used inside classes that are templates. |
|---|
| 125 | Suppose we have a template-class that requires an unsigned integral type with |
|---|
| 126 | at least 16-bits of precision as a template argument, we can achieve this |
|---|
| 127 | using something like this: |
|---|
| 128 | |
|---|
| 129 | #include <climits> |
|---|
| 130 | #include <boost/static_assert.hpp> |
|---|
| 131 | |
|---|
| 132 | template <class UnsignedInt> |
|---|
| 133 | class myclass |
|---|
| 134 | { |
|---|
| 135 | private: |
|---|
| 136 | BOOST_STATIC_ASSERT((std::numeric_limits<UnsignedInt>::digits >= 16) |
|---|
| 137 | && std::numeric_limits<UnsignedInt>::is_specialized |
|---|
| 138 | && std::numeric_limits<UnsignedInt>::is_integer |
|---|
| 139 | && !std::numeric_limits<UnsignedInt>::is_signed); |
|---|
| 140 | public: |
|---|
| 141 | /* details here */ |
|---|
| 142 | }; |
|---|
| 143 | |
|---|
| 144 | [endsect] |
|---|
| 145 | |
|---|
| 146 | [section:templates Use in templates] |
|---|
| 147 | |
|---|
| 148 | Normally static assertions when used inside a class or function template, |
|---|
| 149 | will not be instantiated until the template in which it is used is instantiated. |
|---|
| 150 | However, there is one potential problem to watch out for: if the static assertion |
|---|
| 151 | is not dependent upon one or more template parameters, then the compiler is |
|---|
| 152 | permitted to evaluate the static assertion at the point it is first seen, |
|---|
| 153 | irrespective of whether the template is ever instantiated, for example: |
|---|
| 154 | |
|---|
| 155 | template <class T> |
|---|
| 156 | struct must_not_be_instantiated |
|---|
| 157 | { |
|---|
| 158 | BOOST_STATIC_ASSERT(false); |
|---|
| 159 | }; |
|---|
| 160 | |
|---|
| 161 | Will produce a compiler error with some compilers (for example Intel 8.1 |
|---|
| 162 | or gcc 3.4), regardless of whether the template is ever instantiated. A |
|---|
| 163 | workaround in cases like this is to force the assertion to be dependent |
|---|
| 164 | upon a template parameter: |
|---|
| 165 | |
|---|
| 166 | template <class T> |
|---|
| 167 | struct must_not_be_instantiated |
|---|
| 168 | { |
|---|
| 169 | // this will be triggered if this type is instantiated |
|---|
| 170 | BOOST_STATIC_ASSERT(sizeof(T) == 0); |
|---|
| 171 | }; |
|---|
| 172 | |
|---|
| 173 | |
|---|
| 174 | [endsect] |
|---|
| 175 | |
|---|
| 176 | [endsect] |
|---|
| 177 | |
|---|
| 178 | [section:how How it works] |
|---|
| 179 | |
|---|
| 180 | `BOOST_STATIC_ASSERT` works as follows. There is class `STATIC_ASSERTION_FAILURE` |
|---|
| 181 | which is defined as: |
|---|
| 182 | |
|---|
| 183 | namespace boost{ |
|---|
| 184 | |
|---|
| 185 | template <bool> struct STATIC_ASSERTION_FAILURE; |
|---|
| 186 | |
|---|
| 187 | template <> struct STATIC_ASSERTION_FAILURE<true>{}; |
|---|
| 188 | |
|---|
| 189 | } |
|---|
| 190 | |
|---|
| 191 | The key feature is that the error message triggered by the undefined |
|---|
| 192 | expression `sizeof(STATIC_ASSERTION_FAILURE<0>)`, tends to be consistent |
|---|
| 193 | across a wide variety of compilers. The rest of the machinery of |
|---|
| 194 | `BOOST_STATIC_ASSERT` is just a way to feed the `sizeof` expression into a `typedef`. |
|---|
| 195 | The use of a macro here is somewhat ugly; however boost members have spent |
|---|
| 196 | considerable effort trying to invent a static assert that avoided macros, |
|---|
| 197 | all to no avail. The general conclusion was that the good of a static assert |
|---|
| 198 | working at namespace, function, and class scope outweighed the ugliness of a macro. |
|---|
| 199 | |
|---|
| 200 | [endsect] |
|---|
| 201 | |
|---|
| 202 | [section:test Test Programs] |
|---|
| 203 | |
|---|
| 204 | [table Test programs provided with static_assert |
|---|
| 205 | [[Test Program][Expected to Compile][Description]] |
|---|
| 206 | |
|---|
| 207 | [[[@../../libs/static_assert/static_assert_test.cpp static_assert_test.cpp]] [Yes] [Illustrates usage, and should always compile, really just tests compiler compatibility.]] |
|---|
| 208 | [[[@../../libs/static_assert/static_assert_example_1.cpp static_assert_example_1.cpp]] [Platform dependent.] [Namespace scope test program, may compile depending upon the platform. ]] |
|---|
| 209 | [[[@../../libs/static_assert/static_assert_example_2.cpp static_assert_example_2.cpp]] [Yes] [Function scope test program. ]] |
|---|
| 210 | [[[@../../libs/static_assert/static_assert_example_3.cpp static_assert_example_3.cpp]] [Yes] [Class scope test program. ]] |
|---|
| 211 | [[[@../../libs/static_assert/static_assert_test_fail_1.cpp static_assert_test_fail_1.cpp]] [No] [Illustrates failure at namespace scope. ]] |
|---|
| 212 | [[[@../../libs/static_assert/static_assert_test_fail_2.cpp static_assert_test_fail_2.cpp]] [No] [Illustrates failure at non-template function scope. ]] |
|---|
| 213 | [[[@../../libs/static_assert/static_assert_test_fail_3.cpp static_assert_test_fail_3.cpp]] [No] [Illustrates failure at non-template class scope. ]] |
|---|
| 214 | [[[@../../libs/static_assert/static_assert_test_fail_4.cpp static_assert_test_fail_4.cpp]] [No] [Illustrates failure at non-template class scope. ]] |
|---|
| 215 | [[[@../../libs/static_assert/static_assert_test_fail_5.cpp static_assert_test_fail_5.cpp]] [No] [Illustrates failure at template class scope. ]] |
|---|
| 216 | [[[@../../libs/static_assert/static_assert_test_fail_6.cpp static_assert_test_fail_6.cpp]] [No] [Illustrates failure at template class member function scope. ]] |
|---|
| 217 | [[[@../../libs/static_assert/static_assert_test_fail_7.cpp static_assert_test_fail_7.cpp]] [No] [Illustrates failure of class scope example. ]] |
|---|
| 218 | [[[@../../libs/static_assert/static_assert_test_fail_8.cpp static_assert_test_fail_8.cpp]] [No] [Illustrates failure of function scope example. ]] |
|---|
| 219 | [[[@../../libs/static_assert/static_assert_test_fail_9.cpp static_assert_test_fail_9.cpp]] [No] [Illustrates failure of function scope example (part 2). ]] |
|---|
| 220 | |
|---|
| 221 | ] |
|---|
| 222 | |
|---|
| 223 | [endsect] |
|---|
| 224 | |
|---|
| 225 | |
|---|
| 226 | |
|---|