Skip to content

Commit 98954e7

Browse files
committed
Merge Boost.StaticAssert into Boost.Config.
This merges the sources, documentation, tests and examples of Boost.StaticAssert into Boost.Config. Documentation has been updated to be a part of Boost.Config documentation, the rest is unchanged and at the state of Boost 1.90.0 release (https://github.com/boostorg/static_assert/tree/boost-1.90.0).
1 parent 845fd03 commit 98954e7

20 files changed

+1007
-0
lines changed

doc/config.qbk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Distributed under the Boost Software License, Version 1.0.
4949

5050
[include configuring_boost.qbk]
5151
[include macro_reference.qbk]
52+
[include static_assert.qbk]
5253
[include build_time.qbk]
5354
[include cstdint.qbk]
5455
[include guidelines.qbk]

doc/static_assert.qbk

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

example/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright 2018, 2019 Peter Dimov
2+
# Distributed under the Boost Software License, Version 1.0.
3+
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
4+
5+
include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST)
6+
7+
if(HAVE_BOOST_TEST)
8+
9+
boost_test_jamfile(FILE Jamfile.v2 LINK_LIBRARIES Boost::config Boost::type_traits)
10+
11+
endif()

example/Jamfile.v2

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# copyright John Maddock 2003
2+
# Use, modification and distribution are subject to the
3+
# Boost Software License, Version 1.0. (See accompanying file
4+
# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5+
6+
# bring in the rules for testing
7+
import testing ;
8+
9+
project : requirements
10+
<library>/boost/config//boost_config
11+
<library>/boost/type_traits//boost_type_traits
12+
;
13+
14+
#run static_assert_example_1.cpp ;
15+
run static_assert_example_2.cpp ;
16+
run static_assert_example_3.cpp ;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// (C) Copyright Steve Cleary & John Maddock 2000.
2+
// Use, modification and distribution are subject to the
3+
// Boost Software License, Version 1.0. (See accompanying file
4+
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5+
6+
// See http://www.boost.org for most recent version including documentation.
7+
8+
#include <climits>
9+
#include <cwchar>
10+
#include <limits>
11+
#include <boost/static_assert.hpp>
12+
13+
#if !defined(WCHAR_MIN)
14+
#define WCHAR_MIN 0
15+
#endif
16+
17+
namespace boost{
18+
19+
namespace my_conditions {
20+
BOOST_STATIC_ASSERT(std::numeric_limits<int>::digits >= 32);
21+
BOOST_STATIC_ASSERT(WCHAR_MIN >= 0);
22+
23+
} // namespace my_conditions
24+
25+
} // namespace boost
26+
27+
int main()
28+
{
29+
return 0;
30+
}
31+
32+
33+
34+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// (C) Copyright John Maddock 2000.
2+
// Use, modification and distribution are subject to the
3+
// Boost Software License, Version 1.0. (See accompanying file
4+
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5+
6+
// See http://www.boost.org for most recent version including documentation.
7+
8+
#include <boost/static_assert.hpp>
9+
#include <boost/type_traits.hpp>
10+
#include <iterator>
11+
#include <list>
12+
#include <deque>
13+
14+
template <class RandomAccessIterator >
15+
RandomAccessIterator foo(RandomAccessIterator from, RandomAccessIterator /*to*/)
16+
{
17+
// this template can only be used with
18+
// random access iterators...
19+
typedef typename std::iterator_traits< RandomAccessIterator >::iterator_category cat;
20+
BOOST_STATIC_ASSERT((boost::is_convertible<cat, const std::random_access_iterator_tag&>::value));
21+
//
22+
// detail goes here...
23+
return from;
24+
}
25+
26+
int main()
27+
{
28+
std::deque<int> d;
29+
std::list<int> l;
30+
foo(d.begin(), d.end()); // OK
31+
//foo(l.begin(), l.end()); // error
32+
return 0;
33+
}
34+
35+
36+
37+
38+
39+
40+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// (C) Copyright John Maddock 2000.
2+
// Use, modification and distribution are subject to the
3+
// Boost Software License, Version 1.0. (See accompanying file
4+
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5+
6+
// See http://www.boost.org for most recent version including documentation.
7+
8+
#include <limits>
9+
#include <boost/limits.hpp>
10+
#include <boost/static_assert.hpp>
11+
12+
template <class UnsignedInt>
13+
class myclass
14+
{
15+
private:
16+
BOOST_STATIC_ASSERT((std::numeric_limits<UnsignedInt>::digits >= 16)
17+
&& std::numeric_limits<UnsignedInt>::is_specialized
18+
&& std::numeric_limits<UnsignedInt>::is_integer
19+
&& !std::numeric_limits<UnsignedInt>::is_signed);
20+
public:
21+
/* details here */
22+
};
23+
24+
myclass<unsigned> m1; // this should be OK
25+
//myclass<int> m2; // this should fail
26+
//myclass<unsigned char> m3; // and so should this
27+
28+
int main()
29+
{
30+
return 0;
31+
}
32+
33+

0 commit comments

Comments
 (0)