mirror of
https://github.com/boostorg/website.git
synced 2026-01-19 16:52:15 +00:00
408 lines
15 KiB
HTML
408 lines
15 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
|
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
|
<head>
|
|
<title>Coding Guidelines for Integral Constant Expressions</title>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<link rel="icon" href="/favicon.ico" type="image/ico" />
|
|
<link rel="stylesheet" type="text/css" href=
|
|
"/style-v2/section-development.css" />
|
|
<!--[if IE 7]> <style type="text/css"> body { behavior: url(/style-v2/csshover3.htc); } </style> <![endif]-->
|
|
<script defer data-domain="original.boost.org" src="https://plausible.io/js/script.js"></script></head><!--
|
|
Note: Editing website content is documented at:
|
|
https://www.boost.org/development/website_updating.html
|
|
-->
|
|
|
|
<body>
|
|
<div id="heading">
|
|
<!--#include virtual="/common/heading.html" -->
|
|
</div>
|
|
|
|
<div id="body">
|
|
<div id="body-inner">
|
|
<div id="content">
|
|
<div class="section" id="intro">
|
|
<div class="section-0">
|
|
<div class="section-title">
|
|
<h1>Coding Guidelines for Integral Constant Expressions</h1>
|
|
</div>
|
|
|
|
<div class="section-body">
|
|
<p>Integral Constant Expressions are used in many places in
|
|
C++; as array bounds, as bit-field lengths, as enumerator
|
|
initialisers, and as arguments to non-type template parameters.
|
|
However many compilers have problems handling integral constant
|
|
expressions; as a result of this, programming using non-type
|
|
template parameters in particular can be fraught with
|
|
difficulty, often leading to the incorrect assumption that
|
|
non-type template parameters are unsupported by a particular
|
|
compiler. This short article is designed to provide a set of
|
|
guidelines and workarounds that, if followed, will allow
|
|
integral constant expressions to be used in a manner portable
|
|
to all the compilers currently supported by boost. Although
|
|
this article is mainly targeted at boost library authors, it
|
|
may also be useful for users who want to understand why boost
|
|
code is written in a particular way, or who want to write
|
|
portable code themselves.</p>
|
|
|
|
<h2>What is an Integral Constant Expression?</h2>
|
|
|
|
<p>Integral constant expressions are described in section 5.19
|
|
of the standard, and are sometimes referred to as "compile time
|
|
constants". An integral constant expression can be one of the
|
|
following:</p>
|
|
|
|
<ol>
|
|
<li>A literal integral value, for example <code>0u</code> or
|
|
<code>3L</code>.</li>
|
|
|
|
<li>An enumerator value.</li>
|
|
|
|
<li>Global integral constants, for example:
|
|
<pre>
|
|
const int my_INTEGRAL_CONSTANT = 3;
|
|
</pre>
|
|
</li>
|
|
|
|
<li>Static member constants, for example:
|
|
<pre>
|
|
struct myclass
|
|
{ static const int value = 0; };
|
|
</pre>
|
|
</li>
|
|
|
|
<li>Member enumerator values, for example:
|
|
<pre>
|
|
struct myclass
|
|
{ enum{ value = 0 }; };
|
|
</pre>
|
|
</li>
|
|
|
|
<li>Non-type template parameters of integral or enumerator
|
|
type.</li>
|
|
|
|
<li>The result of a <code>sizeof</code> expression, for
|
|
example:
|
|
<pre>
|
|
sizeof(foo(a, b, c))
|
|
</pre>
|
|
</li>
|
|
|
|
<li>The result of a <code>static_cast</code>, where the
|
|
target type is an integral or enumerator type, and the
|
|
argument is either another integral constant expression, or a
|
|
floating-point literal.</li>
|
|
|
|
<li>The result of applying a binary operator to two integral
|
|
constant expressions:
|
|
<pre>
|
|
INTEGRAL_CONSTANT1 op INTEGRAL_CONSTANT2
|
|
</pre>provided that the operator is not an assignment operator, or comma
|
|
operator.
|
|
</li>
|
|
|
|
<li>The result of applying a unary operator to an integral
|
|
constant expression:
|
|
<pre>
|
|
op INTEGRAL_CONSTANT1
|
|
</pre>provided that the operator is not the increment or decrement operator.
|
|
</li>
|
|
</ol>
|
|
|
|
<h2>Coding Guidelines</h2>
|
|
|
|
<p>The following guidelines are declared in no particular order
|
|
(in other words you need to obey all of them - sorry!), and may
|
|
also be incomplete, more guidelines may be added as compilers
|
|
change and/or more problems are encountered.</p>
|
|
|
|
<h3>When declaring constants that are class members always use
|
|
the macro <code>BOOST_STATIC_CONSTANT.</code></h3>
|
|
<pre>
|
|
template <class T>
|
|
struct myclass
|
|
{
|
|
BOOST_STATIC_CONSTANT(int, value = sizeof(T));
|
|
};
|
|
</pre>
|
|
|
|
<p>Rationale: not all compilers support inline initialisation
|
|
of member constants, others treat member enumerators in strange
|
|
ways (they're not always treated as integral constant
|
|
expressions). The BOOST_STATIC_CONSTANT macro uses the most
|
|
appropriate method for the compiler in question.</p>
|
|
|
|
<h3>Don't declare integral constant expressions whose type is
|
|
wider than int.</h3>
|
|
|
|
<p>Rationale: while in theory all integral types are usable in
|
|
integral constant expressions, in practice many compilers limit
|
|
integral constant expressions to types no wider than
|
|
<code>int</code>.</p>
|
|
|
|
<h3>Don't use logical operators in integral constant
|
|
expressions; use template meta-programming instead.</h3>
|
|
|
|
<p>The header <code><boost/type_traits/ice.hpp></code>
|
|
contains a number of workaround templates, that fulfil the role
|
|
of logical operators, for example instead of:</p>
|
|
<pre>
|
|
INTEGRAL_CONSTANT1 || INTEGRAL_CONSTANT2
|
|
</pre>
|
|
|
|
<p>Use:</p>
|
|
<pre>
|
|
::boost::type_traits::ice_or<INTEGRAL_CONSTANT1,INTEGRAL_CONSTANT2>::value
|
|
</pre>
|
|
|
|
<p>Rationale: A number of compilers (particularly the Borland
|
|
and Microsoft compilers), tend to not to recognise integral
|
|
constant expressions involving logical operators as genuine
|
|
integral constant expressions. The problem generally only shows
|
|
up when the integral constant expression is nested deep inside
|
|
template code, and is hard to reproduce and diagnose.</p>
|
|
|
|
<h3>Don't use any operators in an integral constant expression
|
|
used as a non-type template parameter</h3>
|
|
|
|
<p>Rather than:</p>
|
|
<pre>
|
|
typedef myclass<INTEGRAL_CONSTANT1 ==
|
|
INTEGRAL_CONSTANT2> mytypedef;
|
|
</pre>
|
|
|
|
<p>Use:</p>
|
|
<pre>
|
|
typedef myclass< some_symbol>
|
|
mytypedef;
|
|
</pre>
|
|
|
|
<p>Where <code>some_symbol</code> is the symbolic name of a an
|
|
integral constant expression whose value is
|
|
<code>(INTEGRAL_CONSTANT1 == INTEGRAL_CONSTANT2).</code></p>
|
|
|
|
<p>Rationale: the older EDG based compilers (some of which are
|
|
used in the most recent version of that platform's compiler),
|
|
don't recognise expressions containing operators as non-type
|
|
template parameters, even though such expressions can be used
|
|
as integral constant expressions elsewhere.</p>
|
|
|
|
<h3>Always use a fully qualified name to refer to an integral
|
|
constant expression.</h3>
|
|
|
|
<p>For example:</p>
|
|
<pre>
|
|
<code>typedef</code> myclass< ::boost::is_integral<some_type>::value> mytypedef;
|
|
</pre>
|
|
|
|
<p>Rationale: at least one compiler (Borland's), doesn't
|
|
recognise the name of a constant as an integral constant
|
|
expression unless the name is fully qualified (which is to say
|
|
it starts with <code>::</code>).</p>
|
|
|
|
<h3>Always leave a space after a '<code><</code>' and before
|
|
'<code>::</code>'</h3>
|
|
|
|
<p>For example:</p>
|
|
<pre>
|
|
typedef myclass< ::boost::is_integral<some_type>::value> mytypedef;
|
|
^
|
|
ensure there is space here!
|
|
</pre>
|
|
|
|
<p>Rationale: <code><:</code> is a legal digraph in it's own
|
|
right, so <code><::</code> is interpreted as the same as
|
|
<code>[:</code>.</p>
|
|
|
|
<h3>Don't use local names as integral constant expressions</h3>
|
|
|
|
<p>Example:</p>
|
|
<pre>
|
|
template <class T>
|
|
struct foobar
|
|
{
|
|
BOOST_STATIC_CONSTANT(int, temp = computed_value);
|
|
typedef myclass<temp> mytypedef; // error
|
|
};
|
|
</pre>
|
|
|
|
<p>Rationale: At least one compiler (Borland's) doesn't accept
|
|
this.</p>
|
|
|
|
<p>Although it is possible to fix this by using:</p>
|
|
<pre>
|
|
template <class T>
|
|
struct foobar
|
|
{
|
|
BOOST_STATIC_CONSTANT(int, temp = computed_value);
|
|
typedef foobar self_type;
|
|
typedef myclass<(self_type::temp)> mytypedef; // OK
|
|
};
|
|
</pre>
|
|
|
|
<p>This breaks at least one other compiler (VC6), it is better
|
|
to move the integral constant expression computation out into a
|
|
separate traits class:</p>
|
|
<pre>
|
|
template <class T>
|
|
struct foobar_helper
|
|
{
|
|
BOOST_STATIC_CONSTANT(int, value = computed_value);
|
|
};
|
|
|
|
template <class T>
|
|
struct foobar
|
|
{
|
|
typedef myclass< ::foobar_helper<T>::value> mytypedef; // OK
|
|
};
|
|
</pre>
|
|
|
|
<h3>Don't use dependent default parameters for non-type
|
|
template parameters.</h3>
|
|
|
|
<p>For example:</p>
|
|
<pre>
|
|
template <class T, int I = ::boost::is_integral<T>::value> // Error can't deduce value of I in some cases.
|
|
struct foobar;
|
|
</pre>
|
|
|
|
<p>Rationale: this kind of usage fails for Borland C++. Note
|
|
that this is only an issue where the default value is dependent
|
|
upon a previous template parameter, for example the following
|
|
is fine:</p>
|
|
<pre>
|
|
template <class T, int I = 3> // OK, default value is not dependent
|
|
struct foobar;
|
|
</pre>
|
|
|
|
<h2>Unresolved Issues</h2>
|
|
|
|
<p>The following issues are either unresolved or have fixes
|
|
that are compiler specific, and/or break one or more of the
|
|
coding guidelines.</p>
|
|
|
|
<h3>Be careful of numeric_limits</h3>
|
|
|
|
<p>There are three issues here:</p>
|
|
|
|
<ol>
|
|
<li>The header <limits> may be absent - it is
|
|
recommended that you never include <limits> directly
|
|
but use <boost/pending/limits.hpp> instead. This header
|
|
includes the "real" <limits> header if it is available,
|
|
otherwise it supplies it's own std::numeric_limits
|
|
definition. Boost also defines the macro BOOST_NO_LIMITS if
|
|
<limits> is absent.</li>
|
|
|
|
<li>The implementation of std::numeric_limits may be defined
|
|
in such a way that its static-const members may not be usable
|
|
as integral constant expressions. This contradicts the
|
|
standard but seems to be a bug that affects at least two
|
|
standard library vendors; boost defines
|
|
BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS in
|
|
<boost/config.hpp> when this is the case.</li>
|
|
|
|
<li>There is a strange bug in VC6, where the members of
|
|
std::numeric_limits can be "prematurely evaluated" in
|
|
template code, for example:</li>
|
|
</ol>
|
|
<pre>
|
|
template <class T>
|
|
struct limits_test
|
|
{
|
|
BOOST_STATIC_ASSERT(::std::numeric_limits<T>::is_specialized);
|
|
};
|
|
</pre>
|
|
|
|
<p>This code fails to compile with VC6 even though no instances
|
|
of the template are ever created; for some bizarre reason
|
|
<code>::std::numeric_limits<T>::is_specialized</code>
|
|
always evaluates to false, irrespective of what the template
|
|
parameter T is. The problem seems to be confined to expressions
|
|
which depend on std::numeric_limts: for example if you replace
|
|
<code>::std::numeric_limits<T>::is_specialized</code>
|
|
with <code>::boost::is_arithmetic<T>::value</code>, then
|
|
everything is fine. The following workaround also works but
|
|
conflicts with the coding guidelines:</p>
|
|
<pre>
|
|
template <class T>
|
|
struct limits_test
|
|
{
|
|
BOOST_STATIC_CONSTANT(bool, check = ::std::numeric_limits<T>::is_specialized);
|
|
BOOST_STATIC_ASSERT(check);
|
|
};
|
|
</pre>
|
|
|
|
<p>So it is probably best to resort to something like this:</p>
|
|
<pre>
|
|
template <class T>
|
|
struct limits_test
|
|
{
|
|
#ifdef BOOST_MSVC
|
|
BOOST_STATIC_CONSTANT(bool, check = ::std::numeric_limits<T>::is_specialized);
|
|
BOOST_STATIC_ASSERT(check);
|
|
#else
|
|
BOOST_STATIC_ASSERT(::std::numeric_limits<T>::is_specialized);
|
|
#endif
|
|
};
|
|
</pre>
|
|
|
|
<h3>Be careful how you use the sizeof operator</h3>
|
|
|
|
<p>As far as I can tell, all compilers treat sizeof expressions
|
|
correctly when the argument is the name of a type (or a
|
|
template-id), however problems can occur if:</p>
|
|
|
|
<ol>
|
|
<li>The argument is the name of a member-variable, or a local
|
|
variable (code may not compile with VC6).</li>
|
|
|
|
<li>The argument is an expression which involves the creation
|
|
of a temporary (code will not compile with Borland C++).</li>
|
|
|
|
<li>The argument is an expression involving an overloaded
|
|
function call (code compiles but the result is a garbage
|
|
value with Metroworks C++).</li>
|
|
</ol>
|
|
|
|
<h3>Don't use boost::is_convertible unless you have to</h3>
|
|
|
|
<p>Since is_convertible is implemented in terms of the sizeof
|
|
operator, it consistently gives the wrong value when used with
|
|
the Metroworks compiler, and may not compile with the Borland's
|
|
compiler (depending upon the template arguments used).</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="sidebar">
|
|
<!--#include virtual="/common/sidebar-common.html" -->
|
|
<!--#include virtual="/common/sidebar-development.html" -->
|
|
</div>
|
|
|
|
<div class="clear"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="footer">
|
|
<div id="footer-left">
|
|
<div id="revised">
|
|
<p>Revised $Date: 2007-10-22 22:55:52 +0100 (Mon, 22 Oct 2007) $</p>
|
|
</div>
|
|
|
|
<div id="copyright">
|
|
<p>Copyright Dr John Maddock 2001.</p>
|
|
</div><!--#include virtual="/common/footer-license.html" -->
|
|
</div>
|
|
|
|
<div id="footer-right">
|
|
<!--#include virtual="/common/footer-banners.html" -->
|
|
</div>
|
|
|
|
<div class="clear"></div>
|
|
</div>
|
|
</body>
|
|
</html>
|