int_const_guidelines.htm 12 KB

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