<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>

<meta http-equiv="Content-Type" content="text/html;charset=US-ASCII">

<style type="text/css">

body {
  color: #000000;
  background-color: #FFFFFF;
}

del {
  text-decoration: line-through;
  color: #8B0040;
}
ins {
  text-decoration: underline;
  color: #005100;
}

p.example {
  margin: 2em;
}
pre.example {
  margin: 2em;
}
div.example {
  margin: 2em;
}

code.extract {
  background-color: #F5F6A2;
}
pre.extract {
  margin: 2em;
  background-color: #F5F6A2;
  border: 1px solid #E1E28E;
}

p.function {
}

p.attribute {
  text-indent: 3em;
}

blockquote.std {
  color: #000000;
  background-color: #F1F1F1;
  border: 1px solid #D1D1D1;
  padding: 0.5em;
}

blockquote.stddel {
  text-decoration: line-through;
  color: #000000;
  background-color: #FFEBFF;
  border: 1px solid #ECD7EC;
  padding: 0.5em;
}

blockquote.stdins {
  text-decoration: underline;
  color: #000000;
  background-color: #C8FFC8;
  border: 1px solid #B3EBB3;
  padding: 0.5em;
}

table {
  border: 1px solid black;
  border-spacing: 0px;
  border-collapse: collapse;
  margin-left: auto;
  margin-right: auto;
}
th {
  text-align: left;
  vertical-align: top;
  padding: 0.2em;
  border: 1px solid black;
}
td {
  text-align: left;
  vertical-align: top;
  padding: 0.2em;
  border: 1px solid black;
}

</style>


<title>C++ Parametric Number Type Aliases</title>
</head>
<body>
<h1>C++ Parametric Number Type Aliases</h1>

<p>
ISO/IEC JTC1 SC22 WG21 P0102R0 - 2015-09-27
</p>

<p>
Lawrence Crowl, Lawrence@Crowl.org
</p>

<p>
<a href="#Introduction">Introduction</a><br>
<a href="#Solution">Solution</a><br>
<a href="#Issues">Open Issues</a><br>
<a href="#Wording">Wording</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#compliance">17.6.1.3 Frestanding implementations [compliance]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cstdint.syn">18.1 General [support.general]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cstdint.syn">18.4.1 Header <code>&lt;cstdint&gt;</code> [cstdint.syn]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cstdint.parametric">18.4.2 Parametric types [cstdint.parametric]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cstdfloat">18.4+ Floating-point types [cstdfloat]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cstdfloat.syn">18.4+.1 Header <code>&lt;cstdfloat&gt;</code> [cstdfloat.syn]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cstdfloat.parametric">18.4+.2 Parametric types [cstdfloat.parametric]</a><br>
<a href="#Implementation">Implementation</a><br>
</p>


<h2><a name="Introduction">Introduction</a></h2>

<p>
With the introduction of
template non-type parameters, template class partial specialization and
constexpr functions,
it becomes possible to compute the size needed of a built-in numeric type
at compile time.
However, to make that computation effective,
we need a mechanism to map the computed size to a built-in type.
</p>

<p>
We may need to eventually support three arithmetic type categories
(signed integer, unsigned integer, and floating point)
over two bases
(binary and decimal).
The implication is that
any naming should include both category and base.
</p>


<h2><a name="Solution">Solution</a></h2>

<p>
We propose a set of template type aliases
that take the number of bits required of a type as a template parameter
and provide a built-in type.
</p>

<p>
An alternate approach is to specify the number of digits.
These approaches are nearly equivalent in binary,
but will be substantially different in decimal,
and even more so in floating-point
where the exponent digits might also be specified.
</p>

<p>
We sometimes need types that
hold "at least as many bits" and "exactly this many bits".
So, we provide two facilities, one for each.
In addition, we occasionally need to specify the fastest type
for a given number of bits.
</p>

<blockquote>
<pre class="example">
exact_2uint<32> a; // a built-in binary unsigned integer of exactly 32 bits
least_2int<19> a; // a built-in binary signed integer of at least 19 bits
fast_2int<7> a; // the fastest built-in binary signed integer of at least 7 bits
</pre>
</blockquote>

<p>
Putting the base before the type name seems a bit strange,
but it avoids confusion with
the current practice of putting the size after the type name.
</p>

<p>
It is not unusual for two built-in types to have the same size.
We propose a "round towards int" rule when selecting the type.
This approach reduces literal promotion artifacts.
</p>

<p>
Most, if not all, C++ implementations of binary signed integer types
use a two's complement representation.
We propose to require a two's complement representation
for the types referenced by the alias.
In this approach,
we follow the lead of <code>&lt;cstdint&gt;</code>,
but extend it to require the "least" types to also be two's complement.
</p>

<p>
Furthermore, most C++ implementation's floating point types
use an IEEE (IEEE 754-2008 aka ISO/IEC/IEEE 60559:2011)
representation.
(They may or may not implement full operational semantics.)
To ensure machine-to-machine portability,
we propose to require an IEEE representation.
We follow the lead of
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3636.pdf">N3626
Floating-Point Typedefs Having Specified Widths</a>
in the exact specification and size.
</p>

<blockquote>
<pre class="example">
exact_2ieeefloat<64> a; // a built-in float of exactly 64 bits
fast_2ieeefloat<32> a; // the fastest built-in float of at least 32 bits
least_2ieeefloat<80> a; // a built-in float of at least 80 bits
</pre>
</blockquote>

<p>
Because the built-in types available on a platform
may not meet the requirements specified here,
we make these aliases conditionally supported.
</p>

<p>
Finally,
we need a mechanism to determine the largest of each type supported,
in bits.
Ideally, the mechanism could affect conditional compilation.
Therefore, we add macros.
If a type alias is not supported, the value of the macro should be zero.
</p>

<blockquote>
<pre class="example">
#if MAX_BITS_2INT &gt;= 64 // bits in the largest signed integer
#if MAX_BITS_2UINT &gt;= 64 // bits in the largest unsigned integer
#if MAX_BITS_2IEEEFLOAT &gt;= 80 // bits in the largest float
</pre>
</blockquote>


<h2><a name="Issues">Open Issues</a></h2>

<p>
Should we provide a mechanism
to indicate the degree of hardware implementation?
Possible degrees are
full hardware implementation,
full microcode implementation,
hardware or microcode implementation
with trapping for unusual values, or
full software implementation.
Since binaries area often shipped among different implementations of the binary,
a run-time query would be necessary to be effective.
</p>

<p>
What headers should contain these type aliases?
The integer types are perhaps appropriate to <code>&lt;cstdint&gt;</code>.
We anticipate a floating-point equivalent to <code>&lt;cstdint&gt;</code>,
but it does not yet exist.
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3636.pdf">N3626</a>
suggests using <code>&lt;cfloat&gt;</code>,
but that header seems more specific to describing existing floating types,
as <code>&lt;climits&gt;</code> describes existing integer types.
Since it is easier to merge headers than split them,
we choose to specify a <code>&lt;cstdfloat&gt;</code> header.
</p>

<p>
This paper provides no mechanism
for specifying literals of the corresponding type.
Since types are computed,
literals are unlikely to appear in the source.
</p>


<h2><a name="Wording">Wording</a></h2>

<p>
The following wording changes are relative to
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4527.pdf">N4527</a>.
</p>

<h3><a name="compliance">17.6.1.3 Frestanding implementations [compliance]</a></h3>

<p>
Add the following entry to table 16.
</p>

<blockquote class="stdins">
<table>
<tr>
<td>18.4+</td>
<td>Floating-point types</td>
<td><code>&lt;cstdfloat&gt;</code></td>
</tr>
</table>
</blockquote>


<h3><a name="cstdint.syn">18.1 General [support.general]</a></h3>

<p>
Add the following entry to table 29.
</p>

<blockquote class="stdins">
<table>
<tr>
<td>18.4+</td>
<td>Floating-point types</td>
<td><code>&lt;cstdfloat&gt;</code></td>
</tr>
</table>
</blockquote>


<h3><a name="cstdint.syn">18.4.1 Header <code>&lt;cstdint&gt;</code> [cstdint.syn]</a></h3>

<p>
Add the following entries to the synopsis before paragraph 1.
</p>

<blockquote class="stdins">
<pre><code>namespace std {
  template&lt;int bits&gt; alias exact_2int = <var>implementation-defined</var>;
  template&lt;int bits&gt; alias fast_2int = <var>implementation-defined</var>;
  template&lt;int bits&gt; alias least_2int = <var>implementation-defined</var>;
  template&lt;int bits&gt; alias exact_2uint = <var>implementation-defined</var>;
  template&lt;int bits&gt; alias fast_2uint = <var>implementation-defined</var>;
  template&lt;int bits&gt; alias least_2uint = <var>implementation-defined</var>;
}
#define MAX_BITS_2INT <var>implementation-defined</var>;
#define MAX_BITS_2UINT <var>implementation-defined</var>;</code>
</pre>
</blockquote>

<h3><a name="cstdint.parametric">18.4.2 Parametric types [cstdint.parametric]</a></h3>

<p>
Add a new section with the following paragraphs.
</p>

<blockquote class="stdins">

<p>
The aliases below are conditionally supported.
The macro <code>MAX_BITS_2INT</code>
shall give the largest integer size (in bits) 
supported by the aliases.
[<i>Note:</i>
All variants support the same sizes.
&mdash;<i>end note</i>]
If these aliases are not supported, the value shall be <code>0</code>.
Any parameter to the alias
shall be in the range 1 to <code>MAX_BITS_2INT</code>.
</p>

<dl>

<dt><code>template&lt;int bits&gt; alias exact_2int</code></dt>
<dd>
<p>
The alias <code>exact_2int</code>
refers to a built-in signed binary integer type
of exactly <code>bits</code> bits.
If there are two types of the same size,
it refers to the type that is closest to <code>int</code> in promotion order.
The type must represent negative values with two's-complement representation.
</p>
</dd>

<dt><code>template&lt;int bits&gt; alias fast_2int</code></dt>
<dd>
<p>
The alias <code>fast_2int</code>
refers to the fastest built-in signed binary integer type
of at least <code>bits</code> bits.
If there are two types of the same size,
it refers to the type that is closest to <code>int</code> in promotion order.
The type must represent negative values with two's-complement representation.
</p>
</dd>

<dt><code>template&lt;int bits&gt; alias least_2int</code></dt>
<dd>
<p>
The alias <code>least_2int</code>
refers to the smallest built-in signed binary integer type
of at least <code>bits</code> bits.
If there are two types of the same size,
it refers to the type that is closest to <code>int</code> in promotion order.
The type must represent negative values with two's-complement representation.
</p>
</dd>

<dt><code>template&lt;int bits&gt; alias exact_2uint</code></dt>
<dd>
<p>
The alias <code>exact_2uint</code>
refers to a built-in unsigned binary integer type
of exactly <code>bits</code> bits.
If there are two types of the same size,
it refers to the type
that is closest to <code>unsigned int</code> in promotion order.
</p>
</dd>

<dt><code>template&lt;int bits&gt; alias fast_2uint</code></dt>
<dd>
<p>
The alias <code>fast_2uint</code>
refers to the fastest built-in unsigned binary integer type
of at least <code>bits</code> bits.
If there are two types of the same size,
it refers to the type
that is closest to <code>unsigned int</code> in promotion order.
</p>
</dd>

<dt><code>template&lt;int bits&gt; alias least_2uint</code></dt>
<dd>
<p>
The alias <code>least_2uint</code>
refers to the smallest built-in unsigned binary integer type
of at least <code>bits</code> bits.
If there are two types of the same size,
it refers to the type
that is closest to <code>unsigned int</code> in promotion order.
</p>
</dd>

</dl>

</blockquote>

<h3><a name="cstdfloat">18.4+ Floating-point types [cstdfloat]</a></h3>

<p>
After section 18.4, add a new section.
It has no direct contents.
</p>


<h3><a name="cstdfloat.syn">18.4+.1 Header <code>&lt;cstdfloat&gt;</code> [cstdfloat.syn]</a></h3>

<p>
Add a new section.
</p>

<blockquote class="stdins">
<pre><code>namespace std {
  template&lt;int bits&gt; alias exact_2ieeefloat = <var>implementation-defined</var>;
  template&lt;int bits&gt; alias fast_2ieeefloat = <var>implementation-defined</var>;
  template&lt;int bits&gt; alias least_2ieeefloat = <var>implementation-defined</var>;
  template&lt;int bits&gt; alias exact_10ieeefloat = <var>implementation-defined</var>;
  template&lt;int bits&gt; alias fast_10ieeefloat = <var>implementation-defined</var>;
  template&lt;int bits&gt; alias least_10ieeefloat = <var>implementation-defined</var>;
}
#define MAX_BITS_2IEEEFLOAT <var>implementation-defined</var>;
#define MAX_BITS_10IEEEFLOAT <var>implementation-defined</var>;</code>
</pre>
</blockquote>

<h3><a name="cstdfloat.parametric">18.4+.2 Parametric types [cstdfloat.parametric]</a></h3>

<p>
Add a new section with the following paragraphs.
</p>

<blockquote class="stdins">

<p>
The aliases below are conditionally supported.
The macro <code>MAX_BITS_2IEEEFLOAT</code>
shall give the largest binary floating-point size (in bits) 
supported by the aliases.
[<i>Note:</i>
All variants support the same sizes.
&mdash;<i>end note</i>]
If none of these aliases are supported,
the value shall be <code>0</code>.
The parameter to the alias
shall be in the range 1 to <code>MAX_BITS_2IEEEFLOAT</code>.
</p>

<dl>

<dt><code>template&lt;int bits&gt; alias exact_2ieeefloat</code></dt>
<dd>
<p>
The alias <code>exact_2ieeefloat</code>
refers to a built-in binary floating-point type
of exactly <code>bits</code> bits.
If there are two types of the same size,
it refers to the type that is closest to <code>double</code> in promotion order.
The type must use IEEE representation.
</p>
</dd>

<dt><code>template&lt;int bits&gt; alias fast_2ieeefloat</code></dt>
<dd>
<p>
The alias <code>fast_2ieeefloat</code>
refers to the fastest built-in binary floating-point type
of at least <code>bits</code> bits.
If there are two types of the same size,
it refers to the type that is closest to <code>double</code> in promotion order.
The type must use IEEE representation.
</p>
</dd>

<dt><code>template&lt;int bits&gt; alias least_2ieeefloat</code></dt>
<dd>
<p>
The alias <code>least_2ieeefloat</code>
refers to the smallest built-in binary floating-point type
of at least <code>bits</code> bits.
If there are two types of the same size,
it refers to the type that is closest to <code>double</code> in promotion order.
The type must use IEEE representation.
</p>
</dd>

</dl>

<p>
The aliases below are conditionally supported.
The macro <code>MAX_BITS_10IEEEFLOAT</code>
shall give the largest decimal floating point size (in bits) 
supported by the aliases.
[<i>Note:</i>
All variants support the same sizes.
&mdash;<i>end note</i>]
If none of these aliases are supported,
the value shall be <code>0</code>.
The parameter to the alias
shall be in the range 1 to <code>MAX_BITS_10IEEEFLOAT</code>.
</p>

<dl>

<dt><code>template&lt;int bits&gt; alias exact_10ieeefloat</code></dt>
<dd>
<p>
The alias <code>exact_10ieeefloat</code>
refers to a built-in decimal floating-point type
of exactly <code>bits</code> bits.
If there are two types of the same size,
it refers to the type that is closest to <code>double</code> in promotion order.
The type must use IEEE representation.
</p>
</dd>

<dt><code>template&lt;int bits&gt; alias fast_10ieeefloat</code></dt>
<dd>
<p>
The alias <code>fast_10ieeefloat</code>
refers to the fastest built-in decimal floating-point type
of at least <code>bits</code> bits.
If there are two types of the same size,
it refers to the type that is closest to <code>double</code> in promotion order.
The type must use IEEE representation.
</p>
</dd>

<dt><code>template&lt;int bits&gt; alias least_10ieeefloat</code></dt>
<dd>
<p>
The alias <code>least_10ieeefloat</code>
refers to the smallest built-in decimal floating-point type
of at least <code>bits</code> bits.
If there are two types of the same size,
it refers to the type that is closest to <code>double</code> in promotion order.
The type must use IEEE representation.
</p>
</dd>

</dl>

</blockquote>


<h2><a name="Implementation">Implementation</a></h2>

<p>
The following implementation will work on some current systems.
</p>

<pre class="extract"><code>
#define MAX_BITS_2INT 64

template&lt;int bits&gt; struct exact_2int_special;
template&lt;&gt; struct exact_2int_special&lt;8&gt;  { typedef std::int8_t  type; };
template&lt;&gt; struct exact_2int_special&lt;16&gt; { typedef std::int16_t type; };
template&lt;&gt; struct exact_2int_special&lt;32&gt; { typedef std::int32_t type; };
template&lt;&gt; struct exact_2int_special&lt;64&gt; { typedef std::int64_t type; };
template&lt;int bits&gt; using exact_2int = exact_2int_special&lt;bits&gt;::type;

template&lt;int bits&gt; struct fast_2int_special;
template&lt;&gt; struct fast_2int_special&lt;1&gt; { typedef std::int8_t  type; };
template&lt;&gt; struct fast_2int_special&lt;2&gt; { typedef std::int16_t type; };
template&lt;&gt; struct fast_2int_special&lt;3&gt; { typedef std::int32_t type; };
template&lt;&gt; struct fast_2int_special&lt;4&gt; { typedef std::int32_t type; };
template&lt;&gt; struct fast_2int_special&lt;5&gt; { typedef std::int64_t type; };
template&lt;&gt; struct fast_2int_special&lt;6&gt; { typedef std::int64_t type; };
template&lt;&gt; struct fast_2int_special&lt;7&gt; { typedef std::int64_t type; };
template&lt;&gt; struct fast_2int_special&lt;8&gt; { typedef std::int64_t type; };
template&lt;int bits&gt; using fast_2int = fast_2int_special&lt;(bits+7)/8&gt;::type;

template&lt;int bits&gt; struct least_2int_special;
template&lt;&gt; struct least_2int_special&lt;1&gt; { typedef std::int8_t  type; };
template&lt;&gt; struct least_2int_special&lt;2&gt; { typedef std::int16_t type; };
template&lt;&gt; struct least_2int_special&lt;3&gt; { typedef std::int32_t type; };
template&lt;&gt; struct least_2int_special&lt;4&gt; { typedef std::int32_t type; };
template&lt;&gt; struct least_2int_special&lt;5&gt; { typedef std::int64_t type; };
template&lt;&gt; struct least_2int_special&lt;6&gt; { typedef std::int64_t type; };
template&lt;&gt; struct least_2int_special&lt;7&gt; { typedef std::int64_t type; };
template&lt;&gt; struct least_2int_special&lt;8&gt; { typedef std::int64_t type; };
template&lt;int bits&gt; using least_2int = least_2int_special&lt;(bits+7)/8&gt;::type;

template&lt;int bits&gt; struct exact_2uint_special;
template&lt;&gt; struct exact_2uint_special&lt;8&gt;  { typedef std::uint8_t  type; };
template&lt;&gt; struct exact_2uint_special&lt;16&gt; { typedef std::uint16_t type; };
template&lt;&gt; struct exact_2uint_special&lt;32&gt; { typedef std::uint32_t type; };
template&lt;&gt; struct exact_2uint_special&lt;64&gt; { typedef std::uint64_t type; };
template&lt;int bits&gt; using exact_2uint = least_2uint_special&lt;bits&gt;::type;

template&lt;int bits&gt; struct fast_2uint_special;
template&lt;&gt; struct fast_2uint_special&lt;1&gt; { typedef std::uint8_t  type; };
template&lt;&gt; struct fast_2uint_special&lt;2&gt; { typedef std::uint16_t type; };
template&lt;&gt; struct fast_2uint_special&lt;3&gt; { typedef std::uint32_t type; };
template&lt;&gt; struct fast_2uint_special&lt;4&gt; { typedef std::uint32_t type; };
template&lt;&gt; struct fast_2uint_special&lt;5&gt; { typedef std::uint64_t type; };
template&lt;&gt; struct fast_2uint_special&lt;6&gt; { typedef std::uint64_t type; };
template&lt;&gt; struct fast_2uint_special&lt;7&gt; { typedef std::uint64_t type; };
template&lt;&gt; struct fast_2uint_special&lt;8&gt; { typedef std::uint64_t type; };
template&lt;int bits&gt; using fast_2uint = fast_2uint_special&lt;(bits+7)/8&gt;::type;

template&lt;int bits&gt; struct least_2uint_special;
template&lt;&gt; struct least_2uint_special&lt;1&gt; { typedef std::uint8_t  type; };
template&lt;&gt; struct least_2uint_special&lt;2&gt; { typedef std::uint16_t type; };
template&lt;&gt; struct least_2uint_special&lt;3&gt; { typedef std::uint32_t type; };
template&lt;&gt; struct least_2uint_special&lt;4&gt; { typedef std::uint32_t type; };
template&lt;&gt; struct least_2uint_special&lt;5&gt; { typedef std::uint64_t type; };
template&lt;&gt; struct least_2uint_special&lt;6&gt; { typedef std::uint64_t type; };
template&lt;&gt; struct least_2uint_special&lt;7&gt; { typedef std::uint64_t type; };
template&lt;&gt; struct least_2uint_special&lt;8&gt; { typedef std::uint64_t type; };
template&lt;int bits&gt; using least_2uint = least_2uint_special&lt;(bits+7)/8&gt;::type;

#define MAX_BITS_2IEEEFLOAT 80

template&lt;int bits&gt; struct exact_2ieeefloat_special;
template&lt;&gt; struct exact_2ieeefloat_special&lt;32&gt; { typedef float type; };
template&lt;&gt; struct exact_2ieeefloat_special&lt;64&gt; { typedef double type; };
template&lt;&gt; struct exact_2ieeefloat_special&lt;80&gt; { typedef long double type; };
template&lt;int bits&gt; using exact_2ieeefloat
  = least_2ieeefloat_special&lt;bits&gt;::type;

template&lt;int bits&gt; struct fast_2ieeefloat_special;
template&lt;&gt; struct fast_2ieeefloat_special&lt;1&gt; { typedef float type; };
template&lt;&gt; struct fast_2ieeefloat_special&lt;2&gt; { typedef float type; };
template&lt;&gt; struct fast_2ieeefloat_special&lt;3&gt; { typedef double type; };
template&lt;&gt; struct fast_2ieeefloat_special&lt;4&gt; { typedef double type; };
template&lt;&gt; struct fast_2ieeefloat_special&lt;5&gt; { typedef long double type; };
template&lt;int bits&gt; using fast_2ieeefloat
  = fast_2ieeefloat_special&lt;(bits+15)/16&gt;::type;

template&lt;int bits&gt; struct least_2ieeefloat_special;
template&lt;&gt; struct least_2ieeefloat_special&lt;1&gt; { typedef float type; };
template&lt;&gt; struct least_2ieeefloat_special&lt;2&gt; { typedef float type; };
template&lt;&gt; struct least_2ieeefloat_special&lt;3&gt; { typedef double type; };
template&lt;&gt; struct least_2ieeefloat_special&lt;4&gt; { typedef double type; };
template&lt;&gt; struct least_2ieeefloat_special&lt;5&gt; { typedef long double type; };
template&lt;int bits&gt; using least_2ieeefloat
  = least_2ieeefloat_special&lt;(bits+15)/16&gt;::type;

#define MAX_BITS_10IEEEFLOAT 0
</code></pre>

</body>
</html>
