User-Defined Literals: operator""
(C++11)
User defined literals were introduced in C++11, evolved in C++14 and C++17, and are a nice way to write more expressive code.
The general idea behind user defined literals is that they allow to write a value and tack on a term describing what this value represents. For example:
auto const quantity = 42_bottles_of_water;
In this expression, 42 is the value and _bottles_of_water
is the user defined suffix. The expression as a whole is a user defined literal.
A common usage of user defined literals is to represent units, but they can also be used to add meaning to values in more general contexts.
Here is how to write user defined literals in C++11, C++14 and C++17.
Introduction of user defined literals in C++11
To define a user defined suffix, C++11 introduced a new operator: operator""
. To illustrate, consider the following type:
struct MyType { int value_; };
We can define an operator""
to create this type the following way:
MyType operator""_myType(unsigned long long int value) { return MyType{value}; }
This allows us to write user defined literals such as this one:
42_myType
Note that, contrary to the other operators in C++, operator""
doesn't appear at call site. Indeed, the call site doesn't show any ""
's.
This is the gist of it, but user defined literals come with a few restrictions that you need to know in order to use them effectively.
The types allowed in user defined literals
Not all types are allowed for the values in user defined literals (the suffix on the other hand, can be of any type). Indeed, only the following types can be used:
unsigned long long int
to represent integerslong double
to represent floating point numberschar
,wchar_t
,char8_t
(since C++20),char16_t
, andchar32_t
to represent individual charactersconst char*
to represent stringsconst char*
,size_t size
to represent strings, as well as theirchar8_t
(since C++20),char16_t
, andchar32_t
versions
The last two types both allow to represent strings in user defined literals, such as:
"forty-two"_myType
Depending on whether or not you want to size of the string in the prototype of the operator"" you can define it this way:
MyType operator""_myType(const char* string) { // ... }
or that way:
MyType operator""_myType(const char* string, size_t length) { // ... }
What's with the underscore?
In all the above examples, our user defined suffixes start with an underscore followed by a lower case letter. Should it always be the case?
There are two rules about that. The first rule is that user defined suffixes must start with an underscore, except those defined in the standard library (more on those in a moment). So user defined user defined suffixes must start with an underscore.
The second rule is that user defined suffixes are allowed to start with a capital letter, but in this case there must be no space in the prototype between operator"" and the starting underscore of the user defined suffix:
MyType operator""_MyType(unsigned long long int value) // OK { // ... } MyType operator"" _MyType(unsigned long long int value) // NOT OK { // ... } MyType operator"" _myType(unsigned long long int value) // OK { // ...
Minus -
Sign Caveat*
Uses for user defined literals
User defined literals are an interesting tool to make code more expressive. A typical use case for them is to represent units in code, such as distances (meter, mile, etc.), time (as in chrono) or other types of numerical values.
They are also good for describing the type of an input parameter, even though the compiler would fail to enforce correctness. Look at the following piece of code:
andrew.set_weight(70_metres);
In all, user-defined literals are good for:
- automatic conversion of units to a default one
- qualifying input parameters