int_const_guidelines.htm 12 KB

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