Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/more/int_const_guidelines.htm @ 29

Last change on this file since 29 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

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