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