Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/more/int_const_guidelines.htm @ 12

Last change on this file since 12 was 12, checked in by landauf, 17 years ago

added boost

File size: 11.8 KB
Line 
1<html>
2
3<head>
4<meta http-equiv="Content-Type"
5content="text/html; charset=iso-8859-1">
6<meta name="Template"
7content="C:\PROGRAM FILES\MICROSOFT OFFICE\OFFICE\html.dot">
8<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
9<title></title>
10</head>
11
12<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
13
14<h2 align="center">Coding Guidelines for Integral Constant
15Expressions</h2>
16
17<p>Integral Constant Expressions are used in many places in C++;
18as array bounds, as bit-field lengths, as enumerator
19initialisers, and as arguments to non-type template parameters.
20However many compilers have problems handling integral constant
21expressions; as a result of this, programming using non-type
22template parameters in particular can be fraught with difficulty,
23often leading to the incorrect assumption that non-type template
24parameters are unsupported by a particular compiler. This short
25article is designed to provide a set of guidelines and
26workarounds that, if followed, will allow integral constant
27expressions to be used in a manner portable to all the compilers
28currently supported by boost. Although this article is mainly
29targeted at boost library authors, it may also be useful for
30users who want to understand why boost code is written in a
31particular way, or who want to write portable code themselves.</p>
32
33<h3>What is an Integral Constant Expression?</h3>
34
35<p>Integral constant expressions are described in section 5.19 of
36the standard, and are sometimes referred to as &quot;compile time
37constants&quot;. An integral constant expression can be one of
38the following:</p>
39
40<ol>
41    <li>A literal integral value, for example 0u or 3L.</li>
42    <li>An enumerator value.</li>
43    <li>Global integral constants, for example: <font
44        face="Courier New"><code><br>
45        </code></font><code>const int my_INTEGRAL_CONSTANT = 3;</code></li>
46    <li>Static member constants, for example: <br>
47        <code>struct myclass<br>
48        { static const int value = 0; };</code></li>
49    <li>Member enumerator values, for example:<br>
50        <code>struct myclass<br>
51        { enum{ value = 0 }; };</code></li>
52    <li>Non-type template parameters of integral or enumerator
53        type.</li>
54    <li>The result of a <code>sizeof</code> expression, for
55        example:<br>
56        <code>sizeof(foo(a, b, c))</code></li>
57    <li>The result of a <code>static_cast</code>, where the
58        target type is an integral or enumerator type, and the
59        argument is either another integral constant expression,
60        or a floating-point literal.</li>
61    <li>The result of applying a binary operator to two integral
62        constant expressions: <br>
63        <code>INTEGRAL_CONSTANT1 op INTEGRAL_CONSTANT2 <br>
64        p</code>rovided that the operator is not an assignment
65        operator, or comma operator.</li>
66    <li>The result of applying a unary operator to an integral
67        constant expression: <br>
68        <code>op INTEGRAL_CONSTANT1<br>
69        </code>provided that the operator is not the increment or
70        decrement operator.</li>
71</ol>
72
73<p>&nbsp;</p>
74
75<h3>Coding Guidelines</h3>
76
77<p>The following guidelines are declared in no particular order (in
78other words you need to obey all of them - sorry!), and may also
79be incomplete, more guidelines may be added as compilers change
80and/or more problems are encountered.</p>
81
82<p><b><i>When declaring constants that are class members always
83use the macro BOOST_STATIC_CONSTANT.</i></b></p>
84
85<pre>template &lt;class T&gt;
86struct myclass
87{
88   BOOST_STATIC_CONSTANT(int, value = sizeof(T));
89};</pre>
90
91<p>Rationale: not all compilers support inline initialisation of
92member constants, others treat member enumerators in strange ways
93(they're not always treated as integral constant expressions).
94The BOOST_STATIC_CONSTANT macro uses the most appropriate method
95for the compiler in question.</p>
96
97<p><b><i>Don't declare integral constant expressions whose type
98is wider than int.</i></b></p>
99
100<p>Rationale: while in theory all integral types are usable in
101integral constant expressions, in practice many compilers limit
102integral constant expressions to types no wider than <b>int</b>.</p>
103
104<p><b><i>Don't use logical operators in integral constant
105expressions; use template meta-programming instead.</i></b></p>
106
107<p>The header &lt;boost/type_traits/ice.hpp&gt; contains a number
108of workaround templates, that fulfil the role of logical
109operators, for example instead of:</p>
110
111<p><code>INTEGRAL_CONSTANT1 || INTEGRAL_CONSTANT2</code></p>
112
113<p>Use:</p>
114
115<p><code>::boost::type_traits::ice_or&lt;INTEGRAL_CONSTANT1,INTEGRAL_CONSTANT2&gt;::value</code></p>
116
117<p>Rationale: A number of compilers (particularly the Borland and
118Microsoft compilers), tend to not to recognise integral constant
119expressions involving logical operators as genuine integral
120constant expressions. The problem generally only shows up when
121the integral constant expression is nested deep inside template
122code, and is hard to reproduce and diagnose.</p>
123
124<p><b><i>Don't use any operators in an integral constant
125expression used as a non-type template parameter</i></b></p>
126
127<p>Rather than:</p>
128
129<p><code>typedef myclass&lt;INTEGRAL_CONSTANT1 ==
130INTEGRAL_CONSTANT2&gt; mytypedef;</code></p>
131
132<p>Use:</p>
133
134<p><code>typedef myclass&lt; some_symbol&gt; mytypedef;</code></p>
135
136<p>Where <code>some_symbol</code> is the symbolic name of a an
137integral constant expression whose value is <code>(INTEGRAL_CONSTANT1
138== INTEGRAL_CONSTANT2).</code></p>
139
140<p>Rationale: the older EDG based compilers (some of which are
141used in the most recent version of that platform's compiler),
142don't recognise expressions containing operators as non-type
143template parameters, even though such expressions can be used as
144integral constant expressions elsewhere.</p>
145
146<p><b><i>Always use a fully qualified name to refer to an
147integral constant expression.</i></b></p>
148
149<p>For example:</p>
150
151<pre><code>typedef</code> myclass&lt; ::boost::is_integral&lt;some_type&gt;::value&gt; mytypedef;</pre>
152
153<p>Rationale: at least one compiler (Borland's), doesn't
154recognise the name of a constant as an integral constant
155expression unless the name is fully qualified (which is to say it
156starts with ::).</p>
157
158<p><b><i>Always leave a space after a '&lt;' and before '::'</i></b></p>
159
160<p>For example:</p>
161
162<pre><code>typedef</code> myclass&lt; ::boost::is_integral&lt;some_type&gt;::value&gt; mytypedef;
163                ^
164                ensure there is space here!</pre>
165
166<p>Rationale: &lt;: is a legal digraph in it's own right, so &lt;::
167is interpreted as the same as [:.</p>
168
169<p><b><i>Don't use local names as integral constant expressions</i></b></p>
170
171<p>Example:</p>
172
173<pre>template &lt;class T&gt;
174struct foobar
175{
176   BOOST_STATIC_CONSTANT(int, temp = computed_value);
177   typedef myclass&lt;temp&gt; mytypedef;  // error
178};</pre>
179
180<p>Rationale: At least one compiler (Borland's) doesn't accept
181this.</p>
182
183<p>Although it is possible to fix this by using:</p>
184
185<pre>template &lt;class T&gt;
186struct foobar
187{
188   BOOST_STATIC_CONSTANT(int, temp = computed_value);
189   typedef foobar self_type;
190   typedef myclass&lt;(self_type::temp)&gt; mytypedef;  // OK
191};</pre>
192
193<p>This breaks at least one other compiler (VC6), it is better to
194move the integral constant expression computation out into a
195separate traits class:</p>
196
197<pre>template &lt;class T&gt;
198struct foobar_helper
199{
200   BOOST_STATIC_CONSTANT(int, temp = computed_value);
201};
202
203template &lt;class T&gt;
204struct foobar
205{
206   typedef myclass&lt; ::foobar_helper&lt;T&gt;::value&gt; mytypedef;  // OK
207};</pre>
208
209<p><b><i>Don't use dependent default parameters for non-type
210template parameters.</i></b></p>
211
212<p>For example:</p>
213
214<pre>template &lt;class T, int I = ::boost::is_integral&lt;T&gt;::value&gt;  // Error can't deduce value of I in some cases.
215struct foobar;</pre>
216
217<p>Rationale: this kind of usage fails for Borland C++. Note that
218this is only an issue where the default value is dependent upon a
219previous template parameter, for example the following is fine:</p>
220
221<pre>template &lt;class T, int I = 3&gt;  // OK, default value is not dependent
222struct foobar;</pre>
223
224<p>&nbsp;</p>
225
226<h3>Unresolved Issues</h3>
227
228<p>The following issues are either unresolved or have fixes that
229are compiler specific, and/or break one or more of the coding
230guidelines.</p>
231
232<p><b><i>Be careful of numeric_limits</i></b></p>
233
234<p>There are three issues here:</p>
235
236<ol>
237    <li>The header &lt;limits&gt; may be absent - it is
238        recommended that you never include &lt;limits&gt;
239        directly but use &lt;boost/pending/limits.hpp&gt; instead.
240        This header includes the &quot;real&quot; &lt;limits&gt;
241        header if it is available, otherwise it supplies it's own
242        std::numeric_limits definition. Boost also defines the
243        macro BOOST_NO_LIMITS if &lt;limits&gt; is absent.</li>
244    <li>The implementation of std::numeric_limits may be defined
245        in such a way that its static-const members may not be
246        usable as integral constant expressions. This contradicts
247        the standard but seems to be a bug that affects at least
248        two standard library vendors; boost defines
249        BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS in &lt;boost/config.hpp&gt;
250        when this is the case.</li>
251    <li>There is a strange bug in VC6, where the members of std::numeric_limits
252        can be &quot;prematurely evaluated&quot; in template
253        code, for example:</li>
254</ol>
255
256<pre>template &lt;class T&gt;
257struct limits_test
258{
259   BOOST_STATIC_ASSERT(::std::numeric_limits&lt;T&gt;::is_specialized);
260};</pre>
261
262<p>This code fails to compile with VC6 even though no instances
263of the template are ever created; for some bizarre reason <code>::std::numeric_limits&lt;T&gt;::is_specialized
264</code>always evaluates to false, irrespective of what the
265template parameter T is. The problem seems to be confined to
266expressions which depend on std::numeric_limts: for example if
267you replace <code>::std::numeric_limits&lt;T&gt;::is_specialized</code>
268with <code>::boost::is_arithmetic&lt;T&gt;::value</code>, then
269everything is fine. The following workaround also works but
270conflicts with the coding guidelines:</p>
271
272<pre>template &lt;class T&gt;
273struct limits_test
274{
275   BOOST_STATIC_CONSTANT(bool, check = ::std::numeric_limits&lt;T&gt;::is_specialized);
276   BOOST_STATIC_ASSERT(check);
277};</pre>
278
279<p>So it is probably best to resort to something like this:</p>
280
281<pre>template &lt;class T&gt;
282struct limits_test
283{
284#ifdef BOOST_MSVC
285   BOOST_STATIC_CONSTANT(bool, check = ::std::numeric_limits&lt;T&gt;::is_specialized);
286   BOOST_STATIC_ASSERT(check);
287#else
288   BOOST_STATIC_ASSERT(::std::numeric_limits&lt;T&gt;::is_specialized);
289#endif
290};</pre>
291
292<p><b><i>Be careful how you use the sizeof operator</i></b></p>
293
294<p>As far as I can tell, all compilers treat sizeof expressions
295correctly when the argument is the name of a type (or a template-id),
296however problems can occur if:</p>
297
298<ol>
299    <li>The argument is the name of a member-variable, or a local
300        variable (code may not compile with VC6).</li>
301    <li>The argument is an expression which involves the creation
302        of a temporary (code will not compile with Borland C++).</li>
303    <li>The argument is an expression involving an overloaded
304        function call (code compiles but the result is a garbage
305        value with Metroworks C++).</li>
306</ol>
307
308<p><b><i>Don't use boost::is_convertible unless you have to</i></b></p>
309
310<p>Since is_convertible is implemented in terms of the sizeof
311operator, it consistently gives the wrong value when used with
312the Metroworks compiler, and may not compile with the Borland's
313compiler (depending upon the template arguments used).</p>
314
315<hr>
316
317<p><i>© Copyright Dr John Maddock 2001</i></p>
318<p><i>Use, modification and distribution are subject to the Boost Software License,
319    Version 1.0. (See accompanying file <a href="../LICENSE_1_0.txt">LICENSE_1_0.txt</a>
320    or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>)</i></p>
321
322<p>&nbsp;</p>
323
324<p>&nbsp;</p>
325</body>
326</html>
Note: See TracBrowser for help on using the repository browser.