1. Revision History
1.1. Revision 7 - June 17th, 2019
-
Added additional motivating examples (thanks David Stone).
-
Fixed derp in wording (thanks Roger Orr).
-
Evolution Working Group evaluated the paper, passing the
/uz
literals, while denying thez
/ut
literals.t -
Accept the uz/z literal suffixes for integers as in P0330 for C++23?
SF F N A SA 4 19 12 2 0
-
Accept the ut/t literal suffixes for integers as in P0330 for C++23?
SF F N A SA 0 8 15 10 2
-
Going to Core Working Group for C++23!
1.2. Revision 6 - June 17th, 2019
-
Added additional motivating examples (thanks Alberto Escrig).
-
Update wording to reflect against [n4820].
1.3. Revision 5 - February 8th, 2019
-
Added additional motivation regarding template parameters.
-
Add additional feature test macros for each type of suffix.
1.4. Revision 4 - January 21st, 2019
-
Discussed additional reasoning due to
changes with< span >
and others.ssize ( const T & ) -
Wording is now relative to [n4778], the latest C++ Standard working draft.
1.5. Revision 3 - November 26th, 2018
-
Strengthened rationale for the current set of suffixes in §4.1 Using t for ptrdiff_t and zu for size_t?.
1.6. Revision 2 - October 1st, 2018
-
Published as P0330R2; change reply-to and point of contact from Rein Halbersma to JeanHeyd Meneide, who revitalized paper according to feedback from Rein Halbersma, and all of LWG. Overwhelming consensus for it to be a Language Feature instead, proposal rewritten as Language proposal with wording against [n4762].
1.7. Revision 1 - October 12th, 2017
-
Published as P0330R1; expanded the survey of existing literals. Synced the proposed wording with the Working Draft WG21/N4687. Moved the reference implementation from BitBucket to GitHub.
1.8. Revision 0 - November 21st, 2014
-
Initial release; published as N4254.
-
Published as P0330R0; summarized LEWG’s view re N4254; dropped the proposed suffix for ptrdiff_t; changed the proposed suffix for size_t to zu; added survey of existing literal suffixes.
2. Feedback on Revisions
Polls are in the form Strongly in Favor | Favor | Neutral | Against | Strongly Against. The polls on Revision 1 were as follows, from an EWG meeting with joint LWG/EWG participation at the WG21 2017 Albuquerque meeting.
Proposal as presented, i.e., are we OK with the library solution going forward?
0 | 6 | 5 | 7 | 4
We translated this as strong discouragement to pursue this feature as a set of user-defined literals. A second poll was taken.
Do we want to solve this problem with a language feature?
2 | 15 | 0 | 2 | 2
We considered this overwhelming consensus for it to be a language feature instead, culminating in this paper after much feedback.
3. Motivation
Currently | With Proposal |
---|---|
⚠️ - Compiles on 32-bit, truncates (maybe with warnings) on 64-bit ❌ - Compilation error |
✔️ - Compiles with no warnings on 32-bit or 64-bit |
❌ - Compilation error |
✔️ - Compiles with no warnings on 32-bit or 64-bit |
❌ - Compilation error; OR, ⚠️ - Compiles, but becomes excessively verbose with or casts
|
✔️ - Compiles with no warnings on 32-bit or 64-bit |
❌ - Compilation error; OR, ⚠️ - Compiles, but becomes excessively verbose with or casts
|
✔️ - Compiles with no warnings on 32-bit or 64-bit |
Consider this very simple code to print an index and its value:
std :: vector < int > v { 0 , 1 , 2 , 3 }; for ( auto i = 0 ; i < v . size (); ++ i ) { std :: cout << i << ": " << v [ i ] << '\n' ; }
This code can lead to the following warnings:
main . cpp : In function 'int main () ': main . cpp : warning : comparison of integer expressions of different signedness : 'int 'and 'long unsigned int '[ - Wsign - compare ] for ( auto i = 0 ; i < v . size (); ++ i ) { ~~^~~~~~~~~~
It grows worse if a user wants to cache the size rather than query it per-iteration:
std :: vector < int > v { 0 , 1 , 2 , 3 }; for ( auto i = 0 , s = v . size (); i < s ; ++ i ) { /* use both i and v[i] */ }
Resulting in a hard compiler error:
main . cpp : In function 'int main () ': main . cpp : 8 : 10 : error : inconsistent deduction for 'auto ': 'int 'and then 'long unsigned int 'for ( auto i = 0 , s = v . size (); i < s ; ++ i ) { ^~~~
This paper proposes adding a
s literal suffix that creates
literals, making the following warning-free:
for ( auto i = 0 zu ; i < v . size (); ++ i ) { std :: cout << i << ": " << v [ i ] << '\n' ; }
It also makes this code compile without
and similar:
#include <algorithm>#include <vector>int main () { std :: vector < int > v ; /* work with v... */ std :: size_t clamped_space = std :: max ( 0 zu , std :: min ( 54 zu , v . size ()) // error without suffix ); return 0 ; }
More generally:
-
int is the default type deduced from integer literals without suffix;
-
comparisons, signs or conversion ranks with integers can lead to surprising results;
-
-- and now more frequently,size_t
because ofptrdiff_t
-- are nearly impossible to avoid in the standard library for element access orssize ()
members;. size () -
programmer intent and stability is hard to communicate portably with the current set of literals;
-
surprises range from (pedantic) compiler errors to undefined behavior;
-
existing integer suffixes (such as
) are not a general solution, e.g. when switching compilation between 32-bit and 64-bit on common architectures;ul -
template parameters for multiple arguments often clash with what literals have;
-
and, C-style casts and static_casts are verbose.
4. Design
Following the feedback from §2 Feedback on Revisions, we have dropped the
User-Defined Literals and chose a Core Language Literal Suffix. We opine that it would better serve the needs of addressing the motivation.
As a language feature, the design of the suffixes becomes much simpler. The core language only has one format for its integer literal suffixes: the letter(s), with an optional
on either side of the letter(s) to make it unsigned, with the signed variant being the default on most architectures. We did not want to use
because
might mean
to some and there are people working on the
paper currently wherein a suffix such as
might surface. In this case, it would make some small amount of sense for the suffix
to also work for shorts, albeit that might have unforeseen consequences with standard-defined library literals.
The literal suffixes
and
/
alongside
and
/
were chosen to represent signed/unsigned
and
, respectively.
will yield
and
/
will yield
. Like other case-insensitive language literal suffixes, it will accept both
/
and
/
(and
and
alongside of it). This follows the current convention of the core language to be able to place
and
/
in any order / any case for the suffix.
4.1. Using t
for ptrdiff_t
and zu
for size_t
?
Previous invocations of this paper used only
and
/
, mostly because there was no named type that represented what a signed
or an unsigned
was. This made it awkward to place into the C++ wording for the author writing this paper. However, Core Wording experts (thanks Hubert Tong and Jens Maurer!) have helped elucidate that while the type may not have a formal name or type alias in the language, it is perfectly valid to say "the unsigned/signed integer type corresponding to {X}".
4.2. Why bother making a suffix for ptrdiff_t?
With the inclusion of a
free function coming to the standard, this paper advocates for keeping a literal for
. As the paper was going through the Library group earlier,
's design decisions were not coming to a head and thusly the dialogue did not bring this up. With
now headed into C++20 and
with it, having a modifier for
is useful for consistency and helpful for success in a world where developers employ a lot of
and
.
4.3. But what about {insert favorite suffix here}?
We designed the suffixes based on feedback from both EWG and Core members in the 3 mailing list posts corresponding to that discussion. We will take additional polls on the actual suffix desired by the Community before EWG.
For example, it was made clear during discussion that while some people would not lose any sleep over a suffix scheme such as
for
and
/
for
, others were concerned that architectures (such as armv7-apple-darwin) produced answers such as
for
and
for
. They have the same range exponent on this architecture but the type disconnect would likely bother some folks. The current scheme is to avoid such a pairing of incongruent types.
4.4. What about the fixed/least/max (unsigned) int types?
This paper does not propose suffixes for the fixed size, at-least size, and max size integral types in the standard library or the language. This paper is focusing exclusively on
and
. We have also been made aware of another paper which may handle this separately and considers all the design space necessary for such. We feel it would be best left to LEWG to handle such a paper, since they are closer to library types.
5. Impact on the Standard
This feature is purely an extension of the language and has, to the best of our knowledge, no conflict with existing or currently proposed features.
and
are currently not a literal suffix in the language. As a proof of concept, it has a patch in GCC already according to this paper by Ed Smith-Rowland.
6. Proposed wording and Feature Test Macros
The following wording is relative to [n4820].
6.1. Proposed Feature Test Macro
The recommended feature test macro is
.
6.2. Intent
The intent of this paper is to propose 2 language suffixes for integral literals of specific types. One is for
, one is for
. We follow the conventions set out for other literals in the standard. We define the suffix to produce types
and
similar to how §5.13.7 Pointer Literals [lex.nullptr] introduces
.
6.3. Proposed Wording
Modify §5.13.2 Integer Literals [lex.icon] with additional suffixes:
- integer-suffix:
- unsigned-suffix long-suffixopt
- unsigned-suffix long-long-suffixopt
- unsigned-suffix size-suffixopt
- long-suffix unsigned-suffixopt
- long-long-suffix unsigned-suffixopt
- size-suffix unsigned-suffixopt
unsigned-suffix: one of
u Ulong-suffix: one of
l Llong-long-suffix: one of
ll LLsize-suffix: one of
z Z
Append to §5.13.2 Integer Literals [lex.icon]'s Table 7 four additional entries:
Suffix Decimal literal Binary, octal, or hexadecimal literal z or Z the signed integer type corresponding to
size_t the signed integer type corresponding to
size_t Both u or U
and z or Z
size_t
size_t
Append to §14.8 Predefined macro names [cpp.predefined]'s Table 17 with one additional entry:
Macro name Value __cpp_size_t_suffix 201902L
7. Acknowledgements
Thank you to Rein Halbersma, who started this paper and put in the necessary work for r0 and r1. Thank you to Walter E. Brown, who acted as locum on this paper before the Committee twice and gave us valuable feedback on wording. Thank you to Lounge<C++>'s Cicada for encouraging us to write this paper. Thank you to Hubert Tong and Jens Maurer for giving us a few pointers on where in the Core Language to modify things for such a paper and what words to use. Thank you to Tim Song for wording advice.
We appreciate your guidance as we learn to be a better Committee member and represent the C++ community’s needs more more efficiently and effectively in the coming months.