std :: to_signed
and std :: to_unsigned
- Document number:
- P3643R2
- Date:
2025-09-29 - Audience:
- LEWG
- Project:
- ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21
- Reply-to:
- Jan Schultke <janschultke@gmail.com>
- GitHub Issue:
- wg21.link/P3643/github
- Source:
- github.com/eisenwave/cpp-proposals/blob/master/src/to-signed-unsigned.cow
and
function templates
in the style of
.
Contents
Revision history
Changes since R1
Changes since R0
Introduction
Existing developer practice
Dual purpose
Impact on the standard
Design
Constraints
Possible implementation
Wording
Acknowledgements
References
1. Revision history
1.1. Changes since R1
- ported proposal from Bikeshed to COWEL
- added §2.2. Dual purpose
- reordered §4. Design and §5. Possible implementation
- added discussion on constraints in §4. Design
- fixed typo in §6. Wording:
xvalue
1.2. Changes since R0
-
tightened constraints in §6. Wording to exclude
cv-qualified types in general, not just cv
bool - added
comment to feature-test macrofreestanding
2. Introduction
In integer numerics and bit-manipulation code, it is common to implement functionality in terms of the corresponding signed/unsigned type:
This technique technically works, but suffers from some problems:
-
The use of C-style/function-style casts may conflict with the project's style.
When
is used instead, this code becomes substantially more verbose.static_cast -
Since
has to be spelled out in code, abbreviated function templates cannot be used instead (or at least,T
would be required for the cast).decltype ( x ) -
Repeating the type
may be prone to mistakes. Nothing guarantees us thatT
is of typeT
when writing an expressionT
. In larger code samples, mismatching types and variables is a bug waiting to happen. To be safe, we would have to writestd :: make_signed_t < T > ( x )
. However, this still repeats the expressionstd :: make_signed_t < decltype ( x ) > ( x )
.x
The greater the distance between
and the use of
To solve these issues, this proposal adds the function templates
and
,
which deduce
from
.
This is concise and always uses the correct type.
2.1. Existing developer practice
A GitHub code search for
… shows that roughly 13.8K C++ files
already use a non-standard
and
,
or which
to
or
.
By comparison,
… yields 43K C++ files
which use
,
or which
to
.
The proposal [P1682R3] for
had similar rationale, and at the time,
the author was only able to discover 1000 search results for
.
2.2. Dual purpose
In addition to the purpose of changing signedness of integers, the proposed functions have another purpose: mapping other integral and enumeration types onto signed or unsigned integer types.
,
the use of
reduces the amount of
template instantiations below:
Of course, the instantiation of
is added,
but its cost is quickly outweighed by avoiding instantiations
of much larger and complicated templates throughout the code base.
Just like
and
,
and
map the much larger set of integral types
onto the smaller set of signed and unsigned integer types.
This reduces template instantiations and may improve compilation speed and reduce code size.
3. Impact on the standard
This proposal is a pure library extension.
4. Design
This proposal follows precedent:
Similar to
, the proposed functions are located in
.
The naming scheme is based on
and the search results in §2.1. Existing developer practice.
4.1. Constraints
The design of
and
should be SFINAE-friendly because that is useful.
is valid lets us constrain the interface of
.
As for the constraints of the proposed functions, there are multiple options:
-
❌ Only permit signed or unsigned integer types.
This would be needlessly restrictive because e.g.
is also valid (and yields e.g.make_signed < char16_t >
), which makes it possible to implement thesigned short
function in §2. Introduction for thatarithmetic_shift_right
as well. In general, it would make generic programming harder if only some of the integral types were supported.char16_t -
✔️ Permit what
supports. That is, integral or enumeration types other thanmake_signed
. This is proposed. There is no compelling reason from deviating from the restrictions imposed bybool
andmake_signed
, as their restrictions de-facto define for which types a sign conversion makes sense.make_unsigned -
❌ Permit
types. This is out-of scope, and would effectively replaceinteger-like
. Integer-like types are an open set of types, possibly including user-defined types. This effectively turns the proposed function into a customization point. Seeing thatto-unsigned-like
is a concept which only exists in [ranges], the proposed functions should then beinteger-like
andstd :: ranges :: to_signed
. However, the goal of the proposal is to provide a simple numerical function, not add a ranges-specific customization point object.std :: ranges :: to_unsigned -
❌ Permit arithmetic types.
This would mirror
, which is alsostd :: is_signed_v
for floating-point types. This would create a weird asymmetry, wheretrue
is a no-op, andto_signed ( float )
is ill-formed. The result of the proposed functions is always a signed or unsigned integer type, and permittingto_unsigned ( float )
would muddy the waters here.float
5. Possible implementation
6. Wording
The proposed wording is relative to [N5014].
In subclause [version.syn], add the following feature-testing macro:
In subclause [utility.syn], change the synopsis as follows:
In subclause [utility], add a subclause immediately prior to [utility.underlying]:
Sign conversion [utility.sign.conv]
Constraints:
is a cv-unqualified integral or enumeration type other than
.
Returns:
([meta.trans.sign]).
Constraints:
is a cv-unqualified integral or enumeration type other than
.
Returns:
([meta.trans.sign]).
uses Mandates,
is arguably not SFINAE-friendly.
For example,
is ill-formed (?) without being instantiated.
I don't attempt to fix this; I assume that the above specification "just works".
In practice, compilers do not eagerly instantiate
when the constraints of the function template are not satisfied,
so this specification works.
7. Acknowledgements
Thanks to Dalton Messmer for reviewing R1 of this paper, leaving thoughtful comments that contributed to an improved R2 which discusses many design aspects in more detail.