Bit-precise integers
- Document number:
- D3666R0
- Date:
2025-09-07 - Audience:
- SG6, SG22, EWG, LEWG
- Project:
- ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21
- Reply-to:
- Jan Schultke <[email protected]>
- GitHub Issue:
- wg21.link/P3666/github
- Source:
- github.com/Eisenwave/cpp-proposals/blob/master/src/bitint.cow
Contents
Revision history
Introduction
Motivation
Computation beyond 64 bits
Cornerstone of standard library facilities
C ABI compatibility
Resolving issues with the current integer type system
Portable exact-width integers
Core design
Why not a class template?
Full C compatibility requires fundamental types
C compatibility would require an enormous amount of operator overloads etc.
Constructors cannot signal narrowing
Tiny integers are useful in C++
Special deduction rules
Quality of implementation requires a fundamental type
Why the _BitInt
keyword spelling?
Underlying type of enumerations
Should bit-precise integers be optional?
_BitInt(1)
Undefined behavior on signed integer overflow
Permissive implicit conversions
C compatibility
Difficulty of carving out exceptions in the language
Conclusion on implicit conversions
Template argument deduction
No preprocessor changes, for better or worse
Library design
Naming of the alias template
Why no _t
suffix?
format , to_chars , and to_string support for bit-precise integers
Preventing ranges::iota_view ABI break
Bit-precise size_t
, ptrdiff_t
New abs overload
Lack of random number generation support
simd support for bit-precise integers
simd design problems
simd design conclusion
valarray support for bit-precise integers
Broadening is_integral
Miscellaneous library support
Passing bit_int into standard library function templates
Education
Teaching principles
Implementation experience
Impact on the standard
Impact on the core language
Impact on the standard library
Wording
Core
[lex.icon]
[basic.fundamental]
[conv.rank]
[conv.prom]
[dcl.type.general]
[dcl.type.simple]
[dcl.enum]
[temp.deduct.general]
[temp.deduct.type]
[cpp.predefined]
Library
[version.syn]
[cstdint.syn]
[climits.syn]
[stdbit.h.syn]
[range.iota.view]
[alg.foreach]
[alg.search]
[alg.copy]
[alg.fill]
[alg.generate]
[charconv.syn]
[charconv.to.chars]
[charconv.from.chars]
[string.syn]
[string.conversions]
[cmath.syn]
[c.math.abs]
[simd.general]
[numerics.c.ckdint]
[atomics.ref.int]
[atomics.types.int]
Acknowledgements
References
1. Revision history
This is the first revision.
2. Introduction
[N2763] introduced the
set of types to the C23 standard,
and [N2775] further enhanced this feature with literal suffixes.
For example, this feature may be used as follows:
In short, the behavior of these bit-precise integers is as follows:
-
No integer promotion to
takes place.int - Mixed-signedness comparisons, implicit conversions, and other permissive feature are supported.
-
They have lower conversion rank than standard integers,
so an operation between
and_BitInt ( 8 )
yieldsint
, as does an operation withint
where_BitInt ( N )
is the width ofN
. They only have greater conversion rank when their width is greater.int
3. Motivation
3.1. Computation beyond 64 bits
Computation beyond 64-bit bits, such as with 128-bits is immensely useful. A large amount of motivation for 128-bit computation can be found in [P3140R0]. Computations in cryptography, such as for RSA require even 4096-bit integers.
Even when performing most operations using 64-bit integers,
there are certain use cases where temporarily, twice the width is needed.
For example, the implementation of
requires the user of 128-bit arithmetic,
as does arithmetic with 64-bit
fixed-point numbers (e.g.
3.2. Cornerstone of standard library facilities
There are various existing and possible feature library facilities that would greatly benefit from an N-bit integer type:
-
As mentioned above,
the implementation of
requires the use of 128-bit integers.linear_congruential_engine < uint64_t > -
has constructors takingbitset
and aunsigned long long
member function that converts from/to integers. This is clunky and limited considering that bitsets can be much larger thanto_ullong
. Bit-precise integers would be a superior alternative tounsigned long long
here.unsigned long long -
[P3161R4] proposes library features such as
oradd_carry
which produce a wider integer result than the operands. For example:mul_wide Proposals like these are arguably obsolete if the same operation can be expressed by simply casting the operands to an integer with double the width prior to the multiplication.template < class T > struct mul_wide_result { T low_bits ; T high_bits ; } ; template < class T > constexpr mul_wide_result < T > mul_wide ( T x , T y ) noexcept ;
3.3. C ABI compatibility
C++ currently has no portable way to call C functions such as:
While one could rely on the ABI of
and
to be identical in the first overload,
there certainly is no way to portably invoke the second overload.
This compatibility problem is not a hypothetical concern either; it is an urgent problem.
There are already targets with
supported by major compilers,
and used by C developers:
Compiler | Targets | Languages | |
---|---|---|---|
clang 16+ |
|
all | C & C++ |
GCC 14+ |
|
64-bit only | C |
MSVC | ❌ | ❌ | ❌ |
3.4. Resolving issues with the current integer type system
as standardized in C solves multiple issues that
the standard integers (
etc.) have.
Among other problems,
integer promotion can result in unexpected signedness changes.
is a 32-bit signed integer (which it is on many platforms).
During the multiplication
,
is promoted to
,
and the result of the multiplication
is not representable as a 32-bit signed integer.
Therefore, signed integer overflow takes places … given unsigned operands.
is an alias for
and gets promoted to
.
Surprisingly,
is not
because
is promoted to
in
,
so the subsequent right-shift by
shifts one set bit into
from the left.
Even more surprisingly, if we had used
instead of
for
,
would be
,
despite our code seemingly using only unsigned integers.
Overall, the current integer promotion semantics are extremely surprising
and make it hard to write correct code involving promotable unsigned integers.
Promotion also makes it hard to expose small integers (e.g. 10-bit unsigned integer)
that exist in hardware (e.g. FPGA) in the language,
since all operations would be performed using
.
Unconventional hardware such as FPGAs are pillar of the motivation for
laid out in [N2763].
3.5. Portable exact-width integers
There is no portable way to use an integer with exactly 32 bits in standard C++.
and
may be wider,
and
is an optional type alias
which only exists if such an integer type has no padding bits.
Having additional non-padding bits may be undesirable when implementing serialization,
networking, etc. where the underlying file format or network protocol is specified
using exact widths.
While most platforms support 32-bit integers as
,
their optionality is a problem for use in the standard library and other ultra-portable libraries.
There are many use cases where padding bits would be an acceptable sacrifice
in exchange for writing portable code,
and bit-precise integers fill that gap in the language.
4. Core design
The overall design strategy is as follows:
- The proposal is a C compatibility proposal first and foremost. Whenever possible, we match the behavior of the C type.
-
The goal is to deliver a minimal viable product (MVP)
which can be integrated into the standard as quickly as possible.
This gives us plenty of time to add standard library support wherever desirable over time,
as well as other convenience features surrounding
._BitInt
4.1. Why not a class template?
[P3639R0] explored in detail whether to make it a fundamental type or a library type.
Furthermore, feedback given by SG22 and EWG was to make it a fundamental type, not a library type.
This boils down to two plausible designs
(assuming
is already supported by the compiler), shown below.
𝔽 – Fundamental type | 𝕃 – Library type |
---|---|
The reasons why we should prefer the left side are described in the following subsections.
4.1.1. Full C compatibility requires fundamental types
in C can be used as the type of a bit-field, among other places:
Since C++ does not support the use of class types in bit-fields,
such a
could not be passed from C++ to a C API.
A developer would face severe difficulties
when porting C code which makes use of these capabilities to C++
and if bit-precise integers were a class type in C++.
4.1.2. C compatibility would require an enormous amount of operator overloads etc.
Integer types can be used in a large number of places within the language.
If we wanted a
class type to be used in the same places
(which would be beneficial for C-interoperable code),
we would have to add a significant amount of operator overloads
and user-defined conversion functions:
- There are conversion to/from floating-point types and other integral types.
- There are conversion to/from enumeration types.
-
There are conversion to/from pointers,
at least for
s of the same width as_BitInt
.uintptr_t - Integers can be used to add offsets onto pointers, and by proxy, in the subscript operator of builtin arrays.
-
Arithmetic operators can be used to operate between any mixture of arithmetic types,
such as
._BitInt ( 32 ) + float
Any discrepancies would lead to some code using bit-precise integers behaving differently in C and C++, which is undesirable.
Furthermore, the
is fairly complicated to implement as a library feature
because the resulting type depends on the numeric value of the literal.
This means it would presumably be implemented like:
Seeing that properly emulating C's behavior for
(and its suffixes)
requires a mountain of complicated operator overload sets,
user-defined conversion functions,
converting constructors, and
user-defined literals,
it seems unreasonable to go this direction.
A major selling point of a library type is that library types have more teachable interfaces,
since the user simply needs to look at the declared members of the class
to understand how it works.
If the interface is a record-breaking convoluted mess,
this benefit is lost.
If we choose not to add all this functionality,
then we lose a large portion of C compatibility.
Either option is bad, and making
a fundamental type
seems like the only way out.
4.1.3. Constructors cannot signal narrowing
Some C++ users prefer list initialization because it prevents narrowing conversion. This can prevent some mistakes/questionable code:
This would not be feasible if
was a library type
because narrowing cannot be signaled by constructors.
Consider that
and
should have a non-explicit constructor (template)
accepting
(and other integral types) to enable compatibility in situations like:
If such a
constructor existed,
the following C++ code would not raise any errors:
This code simply calls a
constructor,
and while the initialization of
is spiritually narrowing,
no narrowing conversion actually takes place.
In conclusion,
if
was a library type,
C++ users who use this style would lose what they consider a valuable safety guarantee.
4.1.4. Tiny integers are useful in C++
In some cases, tiny
's may be useful as the underlying type of an enumeration:
By using
rather than
,
every possible value has an enumerator.
If we used e.g.
instead,
there would be 252 other possible values that simply have no name,
and this may be detrimental to compiler optimization of
statements etc.
4.1.5. Special deduction rules
While this proposal focuses on the minimal viable product (MVP), a possible future extension would be new deduction rules allowing the following code:
Being able to make such a call to
is immensely useful because it would allow
for defining a single function template which may be called with every possible
signed integer type,
while only producing a single template instantiation
for
,
, and
,
as long as those three have the same width.
The prospect of being able to write bit manipulation utilities that simply accept
is quite appealing.
If
was a class type,
this would not work because template argument deduction would fail,
even if there existed an implicit conversion sequence from
to
.
These kinds of deduction rules may be shutting the door on this mechanism forever.
4.1.6. Quality of implementation requires a fundamental type
While a library type
gives the implementation
the option to provide no builtin support for bit-precise integers,
to achieve high-quality codegen,
a fundamental type is inevitably needed anyway.
If so,
is arguably adding pointless bloat.
For example, when an integer division has a constant divisor, like
,
it can be optimized to a fixed-point multiplication,
which is much cheaper.
Performing such an optimization requires the compiler to be aware that a division is taking place,
and this fact is lost when division is implemented in software,
as a loop which expands to hundreds of IR instructions.
"Frontend awareness" of these operations is also necessary to provide compiler warnings
when a division by zero or a bit-shift with undefined behavior is spotted.
Use of
on e.g.
cannot be used to achieve this
because numerics code needs to have no hardened preconditions and no contracts,
for performance reasons.
Another workaround would be an ever-growing set of implementation-specific attributes,
but at that point, we may as well make it fundamental.
4.2. Why the _BitInt
keyword spelling?
I also propose to standardize the keyword spelling
and
.
I consider this to a "C compatibility spelling" rather than the preferred one
which is taught to C++ developers.
See also §6.1. Teaching principles.
While a similar approach could be taken
as with the
compatibility macro,
macros cannot be exported from modules,
and macros needlessly complicate the problem compared to a keyword.
Furthermore, to enable compiling shared C and C++ headers, all of the spellings
,
and
need to be valid.
This goes far beyond the capabilities that a compatibility macro like
can provide without language support.
If the
macro simply expanded to
,
this may result in the ill-formed code
.
The most plausible fix would be to create an exposition-only
spelling to enable
,
which makes our users beg the question:
Why is there a compatibility macro for an exposition-only keyword spelling?! Why are we making everything more complicated by not just copying the keyword from C?! Why is this exposition-only when it's clearly useful for users to spell?!
The objections to a keyword spelling are that it's not really necessary, or that it "bifurcates" the language by having two spellings for the same thing, or that those ugly C keywords should not exist in C++. Ultimately, it's not the job of WG21 to police code style; both spellings have a right to exist:
-
The
alias template fits in aesthetically with the rest of the language, and conveys clearly (via "pointy brackets") that the given width is a constant expression.bit_int -
The
spelling is useful for writing C/C++-interoperable code, and C compatibility is an important design goal._BitInt
It seems like both spellings are going to exist,
whether
is a keyword or compatibility macro.
Since there is no clear technical benefit to a macro,
the keyword is the only logical choice.
keyword spelling as a compiler extensions,
so this is standardizing existing practice.
4.3. Underlying type of enumerations
The following C code is ill-formed:
There is no obvious reason why
must not be a valid underlying type.
However, since this feature is not needed for C compatibility,
I do not consider bit-precise integers as underlying types to be part of the MVP.
A follow-up proposal could add this feature later,
possibly in coordination with WG14.
This behavior should be mirrored.
4.4. Should bit-precise integers be optional?
As in C,
is only required to support
of at least
, which has a minimum of
.
This makes
a semi-optional feature,
and it is reasonable to mandate its existence, even in freestanding platforms.
Of course, this has the catch that
may be completely useless
for tasks like 128-bit computation.
As unfortunate as that is, the MVP should include no more than C actually mandates.
Mandating a greater minimum width could be done in a future proposal.
4.5. _BitInt(1)
C23 does not permit
but does permit
,
mostly for historical reasons
(C did not always requires two's complement representation for signed integers).
This is an irregularity that could make generic programming harder in C++.
However, there are already plans to lift the restriction for C2y;
see [N3644].
Following v3 of the proposal,
is expected to be valid type,
and
should be of type
rather than
.
That proposal also contains some practical motivation for why
a single-bit should be permitted.
was allowed,
it would be able to represent the values
and
,
just like an
bit-field.
4.6. Undefined behavior on signed integer overflow
I propose to perpetuate bit-precise integers having undefined behavior
on signed integer overflow, just like
,
etc.
This has a few reasons:
- bit-precise integers have undefined overflow in C, so this is what users are used to.
- "Solving" signed integer overflow for bit-precise integers is not part of the MVP. Undefined behavior can always be defined to do something else, so there is no urgent need for this paper to address this issue, rather than solving it in a follow-up paper.
- Signed integer overflow having undefined behavior is a much broader issue that should be looked at in general, for all integer types, not just bit-precise integer types. Perhaps hardened implementations could have wrapping overflow with erroneous behavior. In any case, the problem exceeds the scope of the paper.
- It is highly unusual that users would expect signed integer overflow to be well-behaved, such as having wrapping behavior. Adding two positive numbers and obtaining a negative number is not typically useful.
-
The undefined behavior here is useful.
It allows for optimizations such as converting
intox + 3 < 0
.x < - 3
4.7. Permissive implicit conversions
Just like any other integral type, the proposal makes bit-precise integers quite permissive when it comes to implicit conversions. This is disappointing to anyone who wants bit-precise integers to be a much "stricter" or "safer" alternative to standard integers, but it is arguably the better design for various reasons.
4.7.1. C compatibility
Firstly, the point is to mirror the C semantics as closely as possible, which leads to few or no surprises when porting code between the languages.
4.7.2. Difficulty of carving out exceptions in the language
Writing C++ code involving bit-precise integers would be quite annoying and "flag" many harmless cases if the rules were too strict.
is "incorrectly signed" for
,
but writing code like this is perfectly reasonable.
To combat this problem, it would be necessary to carve out various special cases. For example, permitting value-preserving conversions with constant expressions would prevent the example above from being flagged. However, such special cases are insufficient to cover all harmless cases.
Even though
is not a constant expression,
will "just work" no matter what integer type
accepts.
Existing C++ code bases that have not used flags such as
Furthermore, discrepancies between the standard integers and bit-precise integers would make it much harder to write generic code:
.
If mixed-sign comparisons were ill-formed for bit-precise integer types,
an instantiation would not be possible with unsigned bit-precise integer types.
:
Even if
is signed instead of unsigned,
produces a mathematically identical result.
4.7.3. Conclusion on implicit conversions
In conclusion, discrepancies between the standard integers and bit-precise
integers are undesirable;
they introduce a lot of unnecessary problems.
There are many harmless operations like
and
where mixing signedness is okay,
and not every user wants to have warnings, let alone errors for these.
Especially errors would make it hard to write headers that compile both in C and in C++.
The final nail in the coffin is that if the user wants implicit conversions to be restricted, they have the freedom to add those restrictions via compiler warnings and linter checks. Having these restrictions standardized in the language robs the user of choice. If C++26 profiles make progress, it is likely that C++ will have profiles which restrict implicit conversions, giving users a standard way to opt into diagnostics.
4.8. Template argument deduction
The following code should be valid:
This would be a consequence of deduction from
being valid:
This behavior is already implemented by Clang as a C++ compiler extension,
and makes deduction behave identically to deducing sizes of arrays.
In general, the aim is to make the deduction of
widths
as similar as possible to arrays because users are already familiar with the latter.
It is also clearly useful because it allows writing templates
that can accept
of any width.
While this behavior could arguably be excluded from the MVP,
it would be extremely surprising to users if such deduction was not possible,
given that appearance of
.
If deducing
from
is possible,
why would it not be possible to deduce
from
?
One thing deliberately not allowed is:
This class-template-argument-deduction-like construct is not part of the MVP and if desired,
should be proposed separately.
Even if it was allowed,
is proposed to be an alias template,
and alias templates do not support "forwarding deduction" to CTAD.
4.9. No preprocessor changes, for better or worse
To my understanding, no changes to the preprocessor are required.
[N2763] did not make any changes to the C preprocessor either.
In most contexts, integer literals in the preprocessor are simply a
Within the controlling constant expression of an
directive,
all signed and unsigned integer types
behave like
and
([cpp.cond]),
which may be surprising.
is a 64-bit signed integer (which it is on many platforms):
is ill-formed
because the integer literal is of type
,
which behaves like
within
.
Since does not fit within
,
the literal is ill-formed ([lex.icon] paragraph 4).
The current behavior could be seen as suboptimal because it makes bit-precise integers dysfunctional within the preprocessor. However, the preprocessor is largely "owned" by C, and any fix should go through WG14. In any case, fixing the C preprocessor is not part of the MVP.
5. Library design
When discussing library design,
it is important to understand that the vast majority of support for bit-precise integers
"sneaks" into the standard without any explicit design changes or wording changes.
Many existing facilities (e.g.
) support any integer type;
adding bit-precise integers to the core language silently adds library support.
The following sections deal mostly with areas of the standard
where some explicit design changes must be made.
5.1. Naming of the alias template
The approach is to expose bit-precise integers via two alias templates:
The goal is to have a spelling reminiscent of the C
spelling.
There are no clear problems with it,
so it is the obvious candidate.
,
, etc.
The alias names as a whole also act as abbreviations of the core language term (which is copied from C):
is a bit-precise signed integer of widthbit_int < N > N
is a bit-precise unsigned integer of widthbit_uint < N > N
5.1.1. Why no _t
suffix?
While the
suffix would be conventional for simple type aliases
such as
,
there is no clear precedent for alias templates.
There are alias templates such as
without any
or
suffix,
but "type trait wrappers" such as
which have a
suffix.
The
suffix does not add any clear benefit,
adds verbosity,
and distances the name from the C spelling
.
Brevity is important here because
is expected to be a commonly spelled type.
A function doing some bit manipulation could use this name numerous times.
5.2. format , to_chars , and to_string support for bit-precise integers
I consider printing support to be part of the MVP for bit-precise integers. There are numerous reasons for this:
- Being able to print bit-precise integers is clearly useful. It seems unthinkable that it would not be supported at some point, even if support was not added by this proposal.
-
Printing support needs to exist in an implementation on some level anyway.
For example,
has support for printing bit-precise integers. Ifprintf
supported printing bit-precise integers but not the idiomatic C++ facilities, it would be a bad look for the language, and it would push users towards type-unsafe functions out of desperation. To be fair,printf
typically "lives" in the system's libc, so this support cannot enable things likeprintf
. However, code may be shared between the libc implementation and the C++ standard library, as is the case in LLVM.constexpr std :: to_chars -
It would take considerable wording effort to exclude
support for bit-precise integers from these facilities,
only for it to be reverted once support is inevitably added.
For example, the expression
printsstd :: println ( " {:b} " , 100 ) 1100100 . This is specified in terms of
wherestd :: to_chars
. Ifbase = 2
does not actually support bit-precise integers, this wording becomes nonsensical.std :: to_chars -
The design is obvious.
No changes to
are necessary ifformat
supports bit-precise integers.to_chars
To facilitate printing and parsing, the following function templates are added:
and
overloads for integral types
are made
by [P3438R0].
If that paper be accepted,
the overloads for bit-precise integers should also be made
for consistency.
is constrained to accept any bit-precise integer type.
It would have also been possible to accept two overloads
taking
and
with some constant template argument instead,
but this doubles the amount of declarations without any clear benefit.
Such a signature is also more future-proof:
the constraints can be relaxed if more types are supported (e.g. extended integer types),
whereas a
parameter can only support bit-precise integer,
until the end of times.
For parsing and printing, this seems short-sighted.
It should also be noted that the existing overloads such as
cannot be removed because it would break existing code.
(but are not
)
may rely on these dedicated overloads:
Analogously, if we replaced all the non-template overloads
and handled all integers in a single function template,
this may break existing valid calls to
etc.
5.3. Preventing ranges::iota_view ABI break
Due to the current wording in [range.iota.view] paragraph 1,
adding bit-precise integers or extended integers of greater width than
potentially forces the implementation to redefine
.
Changing the type would be an ABI break.
This problem is similar to historical issues with
,
where adding 128-bit integers would force the implementation to redefine the former type.
To prevent this, the proposal tweaks the wording in § [range.iota.view] so that new extended or bit-precise integers may be added. Dealing with extended integer types extends slightly beyond the scope of the MVP, but it would be silly to leave the wording in an undesirable state, where adding a 128-bit extended integer still forces an ABI break.
5.4. Bit-precise size_t
, ptrdiff_t
As in C,
the proposal allows for
and
to be bit-precise integers,
which is a consequence of
and pointer subtraction
potentially yielding a bit-precise integer.
Whether bit-precise integers in those places is desirable is for implementers and users to decide, but from the perspective of the C standard and the C++ standard, there is no compelling reason to disallow it. It would be a massive breaking change if existing C++ implementations redefined the type of these, so it is unlikely we will see an implementation that makes use of this freedom anytime soon.
5.5. New abs overload
The proposal adds the following
overload:
While
is not strictly part of the MVP,
taking the absolute of an integer is such a fundamental, easy-to-implement, and useful
operation that we may as well include it here.
5.6. Lack of random number generation support
Support for random number generation is not added
because too many design changes are required,
with non-obvious decisions.
Users can also live without bit-precise integer support in
for a while, so this feature is not part of the MVP.
Wording changes would be needed because
specifically supports certain integer types specified in [rand.req.genl],
rather than having blanket support for bit-precise integers.
Another issue lies with
.
This generator performs modular arithmetic,
which requires double the integer width for intermediate results.
For example,
modular arithmetic is implemented using
in some standard libraries (if available).
An obvious problem for bit-precise integers is how modular arithmetic
for
is meant to be implemented.
We obviously can't just use a wider integer type because none exists.
These and other potential design issues should be explored in a separate paper.
5.7. simd support for bit-precise integers
is one of the few parts in the standard library
where the implementation is highly specific to integer widths,
at least if high implementation quality is needed.
5.7.1. simd design problems
There are many important questions, such as:
-
How do we best optimize
? that type is effectively a bitset.simd :: vec < bit_int < 1 >> - How do we deal with padding bits? Standard integers are typically padding-free, but bit-precise integers are not except for specific sizes.
-
What about
or even greater widths? It seems like this case degenerates into a scalar implementation anyway.simd :: vec < bit_int < 512 >>
It is not obvious whether design changes are needed to properly
support bit-precise integers.
Furthermore, adding a naive implementation for e.g.
would result in an ABI break when being replaced with a more efficient "bit-packed"
implementation later.
5.7.2. simd design conclusion
Due to these design concerns,
I do not consider full
support to be part of the MVP.
However,
support for bit-precise integers is clearly useful,
so a compromise is possible:
support is added only for those bit-precise integers
whose width matches a standard integer type.
This means that a
implementation
"piggy-backs" off of an existing
implementation,
assuming
is a 32-bit signed integer.
Such limited support is easy to provide.
and other
functions.
Those functions accept standard integers
as well as bit-precise integers of matching width.
5.8. valarray support for bit-precise integers
Bit-precise integer support in
is required.
While the same concerns as with
apply in theory,
it is easy to provide a naive implementation,
and the implementation in standard libraries is typically naive anyway,
including for existing integers.
are implemented as a simple loop
rather than being manually optimized with SIMD operations.
5.9. Broadening is_integral
Since bit-precise integer types are integral types,
obviously,
should be
for any bit-precise integer
.
There is a potential concern that existing C++ code constrained using
or
never anticipated that the templates
would be instantiated with huge integers like
.
That is simply a problem we have to live with.
The only way to avoid the issue would be to create a taxonomy of integer types
that is confusing and inconsistent with C
(e.g. by not considering bit-precise integers to be integral types),
or to make
inconsistent with the term "integral type".
Both of these alternatives seem terrible.
5.10. Miscellaneous library support
There are many more standard library parts to which support for bit-precise integers is added. Examples include:
-
C headers such as
,<stdbit.h>
, and<stdio.h>
receive the same degree of support as they have in C. This is the obvious design, and any deviation would need to be justified somehow.<stdckdint.h> -
Various utilities such as
andto_integer
receive support for bit-precise integers. It is implausible that support wouldn't be added in the long run, and the support is added by extending the existing blanket support for integers; no wording changes are needed.hash
5.11. Passing bit_int into standard library function templates
Unlike standard integers,
it is plausible that some bit-precise integers are too large to be passed on the stack,
or at least too large to make this the "default option".
Nonetheless,
all proposed library functions which operate on
should accept
by value.
overload:
If implemented verbatim like this,
in the x86-64 psABI,
would be passed via single register,
would be passed via a pair of registers,
and any wider integer integer would be pushed onto the stack.
Passing via stack is questionable and may result in an immediate program crash
when millions of bits are involved.
The reason for having such signatures is that the details of how values are passed into functions are outside the scope of the standard. Since most functions in the standard are not addressable, and since we don't care about keeping the results of reflecting on the standard library stable, the actual overload sets in the library implementation can differ from the declarations in the standard.
function template could look as follows:
Another plausible implementation strategy is to use an ABI-altering, implementation-specific attribute.
Such an attribute could alter the ABI for
so that it is passed indirectly (via address) beyond a certain size,
not on the stack.
Admittedly, having the standard pass all integers by value may give the user
the false impression that a
function parameter (with unconstrained
)
is idiomatic and harmless, which is problematic.
However, it is seemingly the lesser evil,
since the alternative is wasting LEWG and LWG time on quality of implementation.
6. Education
Following SG20 Education recommendations at Sofia 2025, this proposal contains guidance on how bit-precise integers are meant to be taught by learning resources.
6.1. Teaching principles
-
Emphasize familiar features.
The closest equivalents to
andstd :: bit_int
arestd :: bit_uint
andstd :: intN_t
, respectively.std :: uintN_t -
Clearly distinguish
from other existing integer types. It should be clarified thatstd :: bit_int
is always a distinct type from thestd :: bit_int
aliases, even if it behaves similarly. Furthermore, the major differences are:std :: intN_t -
is not optional (though there exists a maximum width), whereas anystd :: bit_int
may not actually exist.std :: intN_t -
is not subject to integer promotion, unlike any of the existing standard integer types.std :: bit_int -
cannot be used as the underlying type of enumerations.std :: bit_int
-
-
Only reference the
spelling in a note on C compatibility._BitInt
looks nothing like the class templates that C++ users are used to, and nothing suggests that_BitInt ( N )
is required to be a constant expression. TheN
andstd :: bit_int
alias templates should be taught first and foremost.std :: bit_uint -
Point out potential pitfalls:
-
has astd :: bit_int
which is not guaranteed to be any more thanBITINT_MAXWIDTH
. The user should be made aware of this portability problem.64 -
When writing generic code,
the user should be made aware that accepting
in a function signature may be problematic. For all they know,std :: bit_int < N >
could have millions of bits, and this could make the type too large for passing on the stack.std :: bit_int < N >
-
7. Implementation experience
, formerly known as
, has been a compiler extension
in Clang for several years now.
The core language changes are essentially standardizing that compiler extension.
8. Impact on the standard
8.1. Impact on the core language
The core language changes essentially boil down to adding the
type and the
8.2. Impact on the standard library
The impact of adding bit-precise integers to the standard library is quite enormous
because there are many parts of the library
which already support any integer type via blanket wording.
Additionally, bit-precise integer support for various components such as
is explicitly added.
Since this proposal does not explicitly remove support for bit-precise integers,
support "sneaks" its way in, without any explicit wording changes.
For example, use of bit-precise integers in
,
,
,
and many others is enabled.
The addition of bit-precise integers means that (as in the core language),
the
of various containers may be a bit-precise integer,
and
may be bit-precise integers, etc.
Find a summary of affected library components below.
In the interest of reducing noise,
the possible changes to container
s are not listed.
Header | Changes | Wording | See also |
---|---|---|---|
|
Relax some Mandates due to implementability problems. | § [alg.foreach] | §5.10. Miscellaneous library support |
|
Add support for bit-precise integers.
Partial specializations for integral types also support .
|
§ [atomics.ref.int], § [atomics.types.int] |
§5.10. Miscellaneous library support |
|
Expand blanket support for integers. | None required | §5.10. Miscellaneous library support |
|
Add and overloads. |
§ [charconv.syn] | §5.2. |
|
Bit-precise integers can be used in e.g. . |
None required | |
|
Add macro. |
§ [climits.syn] | |
|
Add overload. |
§ [cmath.syn] | §5.5. New |
|
Expand blanket support for integers. | None required | §5.10. Miscellaneous library support |
|
Some concepts broadened (e.g. ). |
None required | §5.9. Broadening |
|
Inherit etc. support for bit-precise integers from C. |
None required | |
|
Expand blanket support for integers. | None required | §5.2. |
|
specializations required as blanket support. |
None required | |
|
Changed indirectly. | § [climits.syn] |
|
|
Expand blanket support for integers. | None required | |
|
Bit-precise integers may be used as an index type. | None required | |
|
Some queries broadened (e.g. ). |
None required | §5.9. Broadening |
|
Expand blanket support for integers ( , saturating arithmetic, etc.) |
None required | |
|
Change to prevent ABI break
when integer types are added.
|
§ [range.iota.view] | §5.3. Preventing |
|
Add limited support for bit-precise integers. | § [simd.general] | §5.7. |
|
Inherit bit-precise integer support from C. | § [stdbit.h.syn] | §5.10. Miscellaneous library support |
|
Inherit bit-precise integer support from C. | § [numerics.c.ckdint] | §5.10. Miscellaneous library support |
|
Changed indirectly. | None required | §5.10. Miscellaneous library support,
|
|
Add and overloads. |
§ [string.conversions] | §5.2. |
|
Changed indirectly. | None required | ,
|
|
Some traits broadened (e.g. ). |
None required | §5.9. Broadening |
|
Expand blanket support for integers (e.g. ). |
None required | §5.10. Miscellaneous library support |
|
Expand blanket support for integers. | None required | §5.8. |
|
Add feature-test macros. | § [version.syn] |
in
,
but
is not mentioned specially in the table above.
9. Wording
The following changes are relative to [N5014].
9.1. Core
quoted
(prose)
spelling of bit-precise integer types should be.
The current spelling is e.g. “
of width ”,
which is fairly similar to other code-heavy spellings like
.
However, this is questionable because
is not valid C++ in itself;
is.
An alternative would be a pure prose spelling, like
bit-precise unsigned integer of width
,
which is a bit more verbose.
There is no strong author preference.
[lex.icon]
In [lex.icon], change the grammar as follows:
integer-suffix :- unsigned-suffix long-suffixopt
- unsigned-suffix long-long-suffixopt
- unsigned-suffix size-suffixopt
- unsigned-suffix bit-precise-int-suffixopt
- long-suffix unsigned-suffixopt
- long-long-suffix unsigned-suffixopt
- size-suffix unsigned-suffixopt
- bit-precise-int-suffix unsigned-suffixopt
unsigned-suffix : one ofu U
long-suffix : one ofl L
long-long-suffix : one ofll LL
size-suffix : one ofz Z
bit-precise-int-suffix : one ofwb WB
Change table [tab:lex.icon.type] as follows:
none |
|
|
or
|
|
|
or
|
|
|
Both or and or
|
|
|
Both or and or
|
|
|
or
|
the signed integer type corresponding to
the type named by
([support.types.layout])
|
the signed integer type corresponding to
the type named by
the type named by
|
Both or and or
|
the type named by
|
the type named by
|
or
|
“ of width ”,
where is the lowest integer
so that the value of the literal can be represented by the type
|
“ of width ”,
where is the lowest integer
so that the value of the literal can be represented by the type
|
Both or and or
|
“ of width ”,
where is the lowest integer
so that the value of the literal can be represented by the type
|
“ of width ”,
where is the lowest integer
so that the value of the literal can be represented by the type
|
quoted
spellings of types
like “
of width ”
in core wording
instead of the
Change [lex.icon] paragraph 4 as follows:
Except for
[Note:
An
or
suffix
is ill-formed if it cannot be represented by
.
An
or
suffix
is ill-formed if it cannot be represented by any bit-precise integer type
because the necessary width is greater than
([climits.syn]).
— end note]
[basic.fundamental]
Change [basic.fundamental] paragraph 1 as follows:
There are five standard signed integer types:
,
,
,
, and
.
In this list,
each type provides at least as much storage as those
preceding it in the list.
There is also a distinct bit-precise signed integer type
“
of width ”
for each ([climits.syn]).
There may also be implementation-defined
extended signed integer types.
The standard, bit-precise, and extended signed integer types are collectively called
signed integer types.
The range of representable values for a signed integer type is
to
(inclusive),
where is called the width of the type.
[Note:
Plain
s are intended to have
the natural width suggested by the architecture of the execution environment;
the other signed integer types are provided to meet special needs.
— end note]
,
but may allow it following [N3644].
Change [basic.fundamental] paragraph 2 as follows:
For each of the standard signed integer types,
there exists a corresponding (but different)
standard unsigned integer type:
,
,
,
, and
.
For each bit-precise signed integer type
“
of width ”,
there exists a corresponding bit-precise unsigned integer type
“
of width ”.
Likewise, for For each of the extended signed integer types,
there exists a corresponding extended unsigned integer type.
The standard, bit-precise, and extended unsigned integer types
are collectively called unsigned integer types.
An unsigned integer type has the same width
as the corresponding signed integer type.
The range of representable values for the unsigned type is
to
(inclusive);
arithmetic for the unsigned type is performed modulo .
[Note: Unsigned arithmetic does not overflow. Overflow for signed arithmetic yields undefined behavior ([expr.pre]). — end note]
Change [basic.fundamental] paragraph 5 as follows:
[…]
The standard signed integer types and standard unsigned integer types
are collectively called the standard integer types, and the
. The bit-precise signed integer types and bit-precise unsigned integer types
are collectively called the bit-precise integer types. The
extended signed integer types and extended
unsigned integer types are collectively called the
extended integer types.
[conv.rank]
Change [conv.rank] paragraph 1 as follows:
Every integer type has an integer conversion rank defined as follows:
-
No two signed integer types other than
andchar
(ifsigned char char is signed) have the same rank, even if they have the same representation. - The rank of a signed integer type is greater than the rank of any signed integer type with a smaller width.
-
The rank of
is greater than the rank oflong long int
, which is greater than the rank oflong int
, which is greater than the rank ofint
, which is greater than the rank ofshort int
.signed char - The rank of any unsigned integer type equals the rank of the corresponding signed integer type.
- The rank of any standard integer type is greater than the rank of any bit-precise integer type with the same width and of any extended integer type with the same width.
-
The rank of
equals the rank ofchar
andsigned char
.unsigned char -
The rank of
is less than the rank of all standard integer types.bool -
The ranks of
,char8_t
,char16_t
, andchar32_t
equal the ranks of their underlying types ([basic.fundamental]).wchar_t - The rank of any extended signed integer type relative to another extended signed integer type with the same width and relative to a bit-precise signed integer type with the same width is implementation-defined, but still subject to the other rules for determining the integer conversion rank.
-
For all integer types
,T1
, andT2
, ifT3
has greater rank thanT1
andT2
has greater rank thanT2
, thenT3
has greater rank thanT1
.T3
[Note: The integer conversion rank is used in the definition of the integral promotions ([conv.prom]) and the usual arithmetic conversions ([expr.arith.conv]). — end note]
[conv.prom]
Change [conv.prom] paragraph 2 as follows:
A prvalue that
- is not a converted bit-field
and, -
has an integer type other than
a bit-precise integer type,
,bool
,char8_t
,char16_t
, orchar32_t
, andwchar_t -
whose integer conversion rank ([conv.rank])
is less than the rank of
int
can be converted to
a prvalue of type
if
can represent all the values of the source type;
otherwise, the source prvalue can be converted to
a prvalue of type
.
Change [conv.prom] paragraph 5 as follows:
A converted bit-field of integral type
other than a bit-precise integer type
can be converted to a prvalue of type
if
can represent all the values of the bit-field;
otherwise, it can be converted to
if
can represent all the values of the bit-field.
[dcl.type.general]
Change [dcl.type.general] paragraph 2 as follows:
As a general rule,
at most one
can be combined with any type specifier except itself.const
can be combined with any type specifier except itself.volatile -
orsigned
can be combined withunsigned
,char
,long
,short or
, or aint bit-precise-int-type-specifier .
orshort
can be combined withlong
.int
can be combined withlong
.double
can be combined withlong
.long
[dcl.type.simple]
Change [dcl.type.simple] paragraph 1 as follows:
The simple type specifiers are
simple-type-specifier :- nested-name-specifieropt type-name
- nested-name-specifier
simple-template-idtemplate - computed-type-specifier
- placeholder-type-specifier
- bit-precise-int-type-specifier
- nested-name-specifieropt template-name
char char8_t char16_t char32_t wchar_t bool short int long signed unsigned float double void type-name :- class-name
- enum-name
- typedef-name
computed-type-specifier :- decltype-specifier
- pack-index-specifier
- splice-type-specifier
bit-precise-int-type-specifier :_BitInt
constant-expression( )
Change table [tab:dcl.type.simple] as follows:
Specifier(s) | Type |
---|---|
the type named | |
the type as defined in [temp.names] | |
the type as defined in [dcl.type.decltype] | |
the type as defined in [dcl.type.pack.index] | |
the type as defined in [dcl.spec.auto] | |
the type as defined in [dcl.type.class.deduct] | |
the type as defined in [dcl.type.splice] | |
|
“ of width ” |
|
“ of width ” |
|
“ of width ” |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Immediately following [dcl.type.simple] paragraph 3, add a new paragraph as follows:
Within a
([expr.const]).
Its value specifies the width
of the bit-precise integer type ([basic.fundamental]).
The program is ill-formed unless
([climits.syn]).
[dcl.enum]
from being the underlying type of enumerations,
matching the current restrictions in C.
See §4.3. Underlying type of enumerations.
Change [dcl.enum] paragraph 2 as follows:
[…]
The
Change [dcl.enum] paragraph 5 as follows:
[…] If the underlying type is not fixed, the type of each enumerator prior ot the closing brace is determined as follows:
-
If an initializer is specified for an enumerator,
the
constant-expression shall be an integral constant expression ([expr.const]) whose type is not a bit-precise integer type. If the expression has unscoped enumeration type, the enumerator has the underlying type of that enumeration type, otherwise it has the same type as the expression. -
If no initializer is specified for the first enumerator,
its type is an unspecified signed
integralinteger type other than a bit-precise integer type. - Otherwise, the type of the enumerator is the same as that of the preceding enumerator, unless the incremented value is not representable in that type, in which case the type is an unspecified integral type other than a bit-precise integer type sufficient to contain the incremented value. If no such type exists, the program is ill-formed.
Change [dcl.enum] paragraph 7 as follows:
For an enumeration whose underlying type is not fixed, the underlying type is an integral type that can represent all the enumerator values defined in the enumeration. If no integral type can represent all the enumerator values, the enumeration is ill-formed. It is implementation-defined which integral type is used as the underlying type, except that
- the underlying type shall not be a bit-precise integer type and
-
the underlying type shall not be larger than
unless the value of an enumerator cannot fit in anint
orint
.unsigned int
If the
[temp.deduct.general]
Add a bullet to [temp.deduct.general] note 8 as follows:
[Note: Type deduction can fail for the following reasons:
- Attempting to instantiate a pack expansion containing multiple packs of differing lengths.
-
Attempting to create an array with an element type that is
, a function type, or a reference type, or attempting to create an array with a size that is zero or negative.void
[Example: — end example]template < class T > int f ( T [ 5 ] ) ; int I = f < int > ( 0 ) ; int j = f < void > ( 0 ) ; // invalid array -
Attempting to create a bit-precise integer type of invalid width ([basic.fundamental]).
[Example: — end example]template < int N > void f ( _BitInt ( N ) ) ; f < 0 > ( 0 ) ; // invalid bit-precise integer - […]
— end note]
[temp.deduct.type]
Change [temp.deduct.type] paragraph 2 as follows:
[…] The type of a type parameter is only deduced from an array bound or bit-precise integer width if it is not otherwise deduced.
Change [temp.deduct.type] paragraph 3 as follows:
A given type
can be composed from a number of other types,
templates, and constant template argument values:
- A function type includes the types of each of the function parameters, the return type, and its exception specification.
- A pointer-to-member type includes the type of the class object pointed to and the type of the member pointed to.
-
A type that is a specialization of a class template (e.g.,
) includes the types, templates, and constant template argument values referenced by the template argument list of the specialization.A < int > - An array type includes the array element type and the value of the array bound.
- A bit-precise integer type includes the integer width.
Change [temp.deduct.type] paragraph 5 as follows:
The non-deduced contexts are:
- […]
-
A constant template argument
or, an array bound, or a bit-precise integer width, in any of which a subexpression references a template parameter.
[Example: — end example]template < size_t N > void f ( _BitInt ( N ) ) ; template < size_t N > void g ( _BitInt ( N + 1 ) ) ; f ( 100 wb ) ; // OK , N = 8 g ( 100 wb ) ; // error: no argument for deduced N - […]
Change [temp.deduct.type] paragraph 8 as follows:
A type template argument
,
a constant template argument
,
a template template argument
denoting a class template or an alias template,
or a template template argument
denoting a variable template or a concept
can be deduced if
and
have one of the following forms:
where […]
Do not change [temp.deduct.type] paragraph 14; it is included here for reference.
The type of
N in the typeT[N] is .std::size_t [Example:
template<typename T> struct S; template<typename T, T n> struct S<int[n]> { using Q = T; }; using V = decltype(sizeof 0); using V = S<int[42]>::Q; // OK; T was deduced asstd::size_t from the typeint[42] — end example]
Immediately following [temp.deduct.type] paragraph 14, insert a new paragraph:
The type of
in the type
is
.
[Example:
T
std :: size_t
_BitInt ( 1 )
— end example]
Change [temp.deduct.type] paragraph 20 as follows:
If
has a form that contains
,
and if the type of
differs from the type of the corresponding template parameter
of the template named by the enclosing
has a form that contains
or
,
and if the type of
is not an integral type, deduction fails.
If
has a form that includes
and the type of
is not
, deduction fails.
[cpp.predefined]
Add a feature-test macro to the table in [cpp.predefined] as follows:
9.2. Library
[version.syn]
Change [version.syn] as follows:
[cstdint.syn]
In [cstdint.syn], update the header synopsis as follows:
Change [cstdint.syn] paragraph 2 as follows:
The header defines all types and macros the same as the C standard library header
and
are not required to be able to represent all values of
bit-precise integer types or of
extended integer types wider than
“
and
“
,
respectively.
Change [cstdint.syn] paragraph 3 as follows:
All types that use the placeholder
,
,
, or
.
The exact-width types
and
for
,
,
, and
are also optional;
however, if an implementation defines integer types
other than bit-precise integer types
with the corresponding width and no padding bits,
it defines the corresponding
[Note:
The macros
and
correspond to the
and
,
respectively.
— end note]
[climits.syn]
In [climits.syn],
add a new line below the definition of
:
Change the synopsis in [climits.syn] paragraph 1 as follows:
The header ,
except that it does not define the macro .
[stdbit.h.syn]
Change [stdbit.h.syn] paragraph 2 as follows:
Mandates:
is an unsigned integer type
- a standard unsigned integer type,
- an extended unsigned integer type, or
- a bit-precise unsigned integer type whose width matches a standard or extended integer type.
[range.iota.view]
Change [range.iota.view] paragraph 1 as follows:
Let
be defined as follows:
-
If
is not an integral type, or if it is an integral type andW
is greater thansizeof ( iter_difference_t < W > )
, thensizeof ( W )
denotesIOTA-DIFF-T ( W )
.iter_difference_t < W > -
Otherwise,
is a standard signed integer type of width greater than the width ofIOTA-DIFF-T ( W )
if such a type exists.W -
Otherwise,
is an unspecified signed-integer-like ([iterator.concept.winc]) type of width not less than the width ofIOTA-DIFF-T ( W )
.W
[alg.foreach]
Change [alg.foreach]
Mandates:
The type
is convertible to an integral type
other than a bit-precise integer type
([conv.integral], [class.conv]).
[…]
Mandates:
The type
is convertible to an integral type
other than a bit-precise integer type
([conv.integral], [class.conv]).
[…]
It is not reasonable to expect millions of additional overloads, and a template that can handle bit-precise integers in bulk could not interoperate with user-defined conversion function templates.
[alg.search]
Change [alg.search] paragraph 5 as follows:
Mandates:
The type
is convertible to an integral type
other than a bit-precise integer type
([conv.integral], [class.conv]).
[alg.copy]
Change [alg.copy] paragraph 15 as follows:
Mandates:
The type
is convertible to an integral type
other than a bit-precise integer type
([conv.integral], [class.conv]).
[alg.fill]
Change [alg.fill] paragraph 2 as follows:
Mandates:
The expression
is writable ([iterator.requirements.general])
to the output iterator.
The type
is convertible to an integral type
other than a bit-precise integer type
([conv.integral], [class.conv]).
[alg.generate]
Change [alg.generate] paragraph 2 as follows:
Mandates:
is convertible to an integral type
other than a bit-precise integer type
([conv.integral], [class.conv]).
[charconv.syn]
Change [charconv.syn] paragraph 1 as follows:
When a function is specified with a type placeholder of
,
the implementation provides overloads for
and all cv-unqualified signed and unsigned integer types
standard and extended integer types
in lieu of
.
When a function is specified with a type placeholder of
,
the implementation provides overloads for all
cv-unqualified floating-point types ([basic.fundamental])
in lieu of
.
[charconv.to.chars]
Change [charconv.to.chars] as follows:
[…]
Constraints:
is a bit-precise integer type.
Preconditions:
has a value between 2 and 36 (inclusive).
[…]
[charconv.from.chars]
Change [charconv.from.chars] as follows:
[…]
Constraints:
is a bit-precise integer type.
Preconditions:
has a value between 2 and 36 (inclusive).
[…]
[string.syn]
Change [string.syn] as follows:
If the existing overloads for integral types
have been made
through [P3438R0] or a subsequent paper,
additionally make the following changes:
[string.conversions]
Change [string.conversions] as follows:
[…]
Constraints:
is a bit-precise or extended integer type.
Returns:
.
[…]
Constraints:
is a bit-precise or extended integer type.
Returns:
.
[…]
If the existing overloads for integral types
have been made
through [P3438R0] or a subsequent paper,
additionally make the following changes:
[cmath.syn]
In [cmath.syn], change the synopsis as follows:
Change [cmath.syn] paragraph 3 as follows:
For each function with at least one parameter of type
other than
,
the implementation also provides additional overloads sufficient to ensure that,
if every argument corresponding to a
parameter
has arithmetic type
other than
[c.math.abs]
Change [c.math.abs] as follows:
Effects:
These functions have the semantics specified in the C standard library for the functions
,
, and
, respectively.
Remarks:
If
is called with an argument of type
for which
is
and if
cannot be converted to
by integral promotion,
the program is ill-formed.
[Note:
Allowing arguments that can be promoted to
provides compatibility with C.
— end note]
Effects:
Equivalent to
.
[Note: The behavior is undefined if
has the lowest possible integer value of its type ([expr.pre]). — end note]
The Effects specification needs to be altered because
for bit-precise integers is a novel invention with no C counterpart.
It also seems like unnecessary indirection to refer to another language standard
for a single expression.
The Remarks specification is removed
because is a usage tutorial and history lesson;
it does not say anything about what
does.
The specification is also factually wrong.
Just because an attempt is made to call
and the overloads above
don't handle it,
doesn't mean that the user doesn't have their own
overload.
In that event, the program is not ill-formed;
overload resolution simply doesn't select one of these functions.
[simd.general]
Change [simd.general] paragraph 2 as follows:
The set of vectorizable types comprises
-
all standard integer types,
character types,
and the types
andfloat
([basic.fundamental]);double - any bit-precise integer type whose width matches a standard integer type;
-
,std :: float16_t
, andstd :: float32_t
if defined ([basic.extended.fp]); andstd :: float64_t -
wherecomplex < T >
is a vectorizable floating-point type.T
[numerics.c.ckdint]
Change [numerics.c.ckdint] as follows:
Mandates:
is a signed or unsigned integer type.
Each of the types
,, and
is a cv-unqualified signed or unsigned integer type
other than a bit-precise integer type.
Remarks: Each function template has the same semantics as the corresponding type-generic macro with the same name specified in ISO/IEC 9899:2024, 7.20.
[atomics.ref.int]
Do not change [atomics.ref.int] paragraph 1; it is provided here for reference:
There are specializations of the
class template for all integral types except
atomic_ref cv . For each such type
bool , the specialization
integral-type provides additional atomic operations appropriate to integral types.
atomic_ref < integral-type >
[atomics.types.int]
Change [atomics.types.int] paragraph 1 as follows:
There are specializations of the
class template for
the integral types
standard integer types,
bit-precise integer types,
character types,
and any other types needed by the typedefs
in the header
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
the specialization
provides additional atomic operations
appropriate to integral types.
[Note:
The specialization
uses the primary template ([atomics.types.generic]).
— end note]
10. Acknowledgements
I thank Jens Maurer and Christof Meerwald for reviewing and correcting the proposal's wording.
I thank Erich Keane and other LLVM contributors for implementing most of the proposed core changes in Clang's C++ frontend, giving this paper years worth of implementation experience in a major compiler without any effort by the author.
I thank Erich Keane, Bill Seymour, Howard Hinnant, JeanHeyd Meneide, Lénárd Szolnoki, Brian Bi, Peter Dimov, Aaron Ballman, Pete Becker, Jens Maurer, Matthias Kretz, Jonathan Wakely, and many others for providing early feedback on this paper, prior papers such as [P3639R0], and the discussion surrounding bit-precise integers as a whole. The paper would not be where it is today without hundreds of messages worth of valuable feedback.