Allowing any unsigned integral type as parameter type for literal operators
Author: MichaĆ Dominiak, griwes@griwes.info
Document number: P0345R0
Date: 2016-05-25
Introduction
User-defined literals are a great tool for shortening code that would otherwise need to be overly verbose,
but since the first proposal, they lacked one feature that would make writing code even simpler - supporting
arbitrary unsigned types as arguments for operator""
. Consider the following code:
constexpr std::uint8_t operator "" _foo(unsigned long long value) { return value; } int main() { auto foo = 1024_foo; // this compiles with no warnings, even though it overflows, whereas this: char bar = 1024; // warns about changing the value }
It should be obvious that the first should also produce a diagnostic, since it might be a result of a
simple programming mistake. There is also another problem, which appears to be far less important, but
still exists. Consider the following platform specific code for a platform, where std::uint64_t
is the biggest unsigned integer type:
constexpr std::uint64_t operator "" _bar(std::uint64_t value) { // ... }
results in an error in both GCC and Clang, because they use unsigned long
, not unsigned
long long
for std::uint64_t
, at least on Linux. This is an environment-specific problem,
but the Standard should provide a way to overcome it in a portable way.
Proposed solution
The proposed solution is as follows:
-
Allow any unsigned type as an argument for
operator ""
, notunsigned long long
only. - Make narrowing in case of user defined literals ill-formed.
An additional feature gained with 1) and 2) is allowing to limit the range of values used in a user-defined literal.
Note: this proposal doesn't propose operator ""
overloading for unsigned
integral types. Allowing such overloading would create ambiguities; it is not desirable.
Proposed wording changes
Change in 13.5.8 over.literal paragraph 3:
The declaration of a literal operator shall have a parameter-declaration-clause equivalent to one of the following:Add two new paragraphs before 13.5.8 over.literal paragraph 5:
const char*
unsigned char
unsigned short int
unsigned int
unsigned long int
unsigned long long int
- an extended unsigned integer type ([basic.fundamental].3)
- ...
Literal operator overloading for unsigned integral types is not supported. If there exist two or more literal operator declarations with the same literal suffix identifier with a single parameter, but of different unsigned integral types, the program is ill-formed.Change in 13.5.8 over.literal paragraph 8:
If a narrowing conversion would happen when a literal operator with a single parameter of an unsigned integral type is invoked implicitly through user-defined literal, the program is ill-formed.
template <char...> int operator "" _j(const char*); // error: invalid parameter-declaration-clause std::uint8_t operator "" _k(std::uint8_t); auto l = 256_k; // error: integer constant is too large for its type std::uint16_t operator "" _k(std::uint16_t); // error: literal operator overloading is not supported