User-defined literals are a unique feature in all mainstream programming languages. They empower you to combine values with units.
The syntax
Literals are explicit values in a program. This can be a boolean like true, the number 3 or 4.15; but this can also be the character 'a' or the C string "hallo". Even the lambda function [](int a, int b){ return a+b; } is a function literal. With C++11 it's possible to generate user-defined literals by adding a suffix to a built-in literal for integers, floating points, characters, and C strings.
User-defined literals have to obey the following syntax: built-in literal + _ + suffix.
Usually, you use the suffix for a unit:
101000101_b
63_s
10345.5_dm
123.45_km
100_m
131094_cm
33_cent
"Hallo"_i18n
But what is the key benefit of user-defined literals? The C++ compiler maps the user-defined literals to the corresponding literal operator. This literal operator has - of course - to be implemented by the programmer.
The magic
Let's have a look at the user-defined literal 0101001000_b that represents a binary value. The compiler maps the user-defined literal 0101001000_b to the literal operator operator"" _b(long long int bin). A few special rules are still missing.
- There has to be a space between the quotation marks ("") and the underscore with suffix (_b).
- You have the binary value (0101001000) in the variable bin.
- If the compiler doesn't find the corresponding literal operator, the compilation will fail.
We get with C++14 an alternative syntax for user-defined types. They differ from the C++11 syntax because it requires no space. Therefore, it is possible to use reserved keywords like _C as a suffix and use a user-defined literal of the form 11_C. The compiler will map 11_C to the literal operator""_C(unsigned long long int). The simple rule is now that you can use suffixes starting with an upper letter.
User-defined literals are the killer feature in modern C++ if you want to write safety-critical software. Why? Thanks to the automatic mapping of the user-defined literal to the literal operator you can implement type-safe arithmetic. The compiler takes care that you don't add apples and pears. Example?
How many meters do I drive on average per week? The question has occupied me for a long time.
Typesafe calculation with distances
Before I deal with the details, here is the main program.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
// average.cpp
#include <distance.h>
#include <unit.h>
using namespace Distance::Unit;
int main(){
std:: cout << std::endl;
std::cout << "1.0_km: " << 1.0_km << std::endl;
std::cout << "1.0_m: " << 1.0_m << std::endl;
std::cout << "1.0_dm: " << 1.0_dm << std::endl;
std::cout << "1.0_cm: " << 1.0_cm << std::endl;
std::cout << std::endl;
std::cout << "0.001 * 1.0_km: " << 0.001 * 1.0_km << std::endl;
std::cout << "10 * 1_dm: " << 10 * 1.0_dm << std::endl;
std::cout << "100 * 1.0cm: " << 100 * 1.0_cm << std::endl;
std::cout << "1_km / 1000: " << 1.0_km / 1000 << std::endl;
std::cout << std::endl;
std::cout << "1.0_km + 2.0_dm + 3.0_dm + 4.0_cm: " << 1.0_km + 2.0_dm + 3.0_dm + 4.0_cm << std::endl;
std::cout << std::endl;
auto work= 63.0_km;
auto workPerDay= 2 * work;
auto abbrevationToWork= 5400.0_m;
auto workout= 2 * 1600.0_m;
auto shopping= 2 * 1200.0_m;
auto distPerWeek1= 4*workPerDay-3*abbrevationToWork+ workout+ shopping;
auto distPerWeek2= 4*workPerDay-3*abbrevationToWork+ 2*workout;
auto distPerWeek3= 4*workout + 2*shopping;
auto distPerWeek4= 5*workout + shopping;
std::cout << "distPerWeek1: " << distPerWeek1 << std::endl;
auto averageDistance= getAverageDistance({distPerWeek1,distPerWeek2,distPerWeek3,distPerWeek4});
std::cout<< "averageDistance: " << averageDistance << std::endl;
std::cout << std::endl;
}
|
The literal operators are implemented in the namespace Distance::unit. You should use namespaces for user-defined literals because name collisions are for two reasons very likely. First, the suffixes are usually very short; second, the suffixes usually stand for units which already established abbreviations. I used in the program the suffixes km, m, dm und cm.
Here is the output of the program. My unit for distances is a meter.

I display in lines 12 - 15 the various distances; I calculate in lines 19 - 22 the meter in various resolutions. The last test looks quite promising.
1.0_km + 2.0_dm + 3.0_dm + 4.0_cm is 1000.54 m (line 54). The compiler takes care of the calculations with all units.
The key question remains. How many meters will I drive on average a week? For convenience, I define a few constants: work, workPerDay, abbrevationToWork, and shopping. These are my building blocks for the 4 weeks (lines 34 - 37). I went 493 km in the first week by car. The function getAverageDisttance (line 41) helps me to get the average. I have to invoke it with an initializer list. I drive 255900m on average per week. That needs to change! And that has changed. I'm now an independent trainer.
Under the hood
I ignored one fact. Where are the MyDistance objects defined? They are hidden in the program behind the automatic type deduction. Therefore, the explicit type for the variable work (line 28) is Distance::Distance. The line 28 is equivalent to Distance::MyDistance work= 63.0_km;

If I use 1.5_km + 105.1_m in the source code, the following steps will automatically happen. The compiler maps at first the suffixes km and m to the corresponding literal operators; at second, the compiler maps the + operator to the overloaded + operator of the MyDistance objects. Both steps can only work if the programmer implements the right operators as part of his contract. This means in this concrete case that he has to implement the literal operator and + operator. The black arrows in the graphic stand for the automatically performed mapping of the compiler. The red arrows stand for the functionality that the programmer has to implement.
What's still missing to make the graphic complete. Right! The meat behind the red arrows.
Tasks of the programmer
At first to the known overloading of operators. I overloaded for the class MyDistance basic arithmetic (line 15 - 28) and the output operator (line 30 - 33). The operators are global functions and can use - thanks to their friendship - the internals of the class. I store in the private variable m the distance. The function getAverageDistance (line 41 - 45) is applying the overloaded addition and division operator.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
// distance.h
#ifndef DISTANCE_H
#define DISTANCE_H
#include <iostream>
#include <ostream>
namespace Distance{
class MyDistance{
public:
MyDistance(double i):m(i){}
friend MyDistance operator+(const MyDistance& a, const MyDistance& b){
return MyDistance(a.m + b.m);
}
friend MyDistance operator-(const MyDistance& a,const MyDistance& b){
return MyDistance(a.m - b.m);
}
friend MyDistance operator*(double m, const MyDistance& a){
return MyDistance(m*a.m);
}
friend MyDistance operator/(const MyDistance& a, int n){
return MyDistance(a.m/n);
}
friend std::ostream& operator<< (std::ostream &out, const MyDistance& myDist){
out << myDist.m << " m";
return out;
}
private:
double m;
};
}
Distance::MyDistance getAverageDistance(std::initializer_list<Distance::MyDistance> inList){
auto sum= Distance::MyDistance{0.0};
for (auto i: inList) sum = sum + i ;
return sum/inList.size();
}
#endif
|
Shorter but more thrilling are the literal operators.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
// unit.h
#ifndef UNIT_H
#define UNIT_H
#include <distance.h>
namespace Distance{
namespace Unit{
MyDistance operator "" _km(long double d){
return MyDistance(1000*d);
}
MyDistance operator "" _m(long double m){
return MyDistance(m);
}
MyDistance operator "" _dm(long double d){
return MyDistance(d/10);
}
MyDistance operator "" _cm(long double c){
return MyDistance(c/100);
}
}
}
#endif
|
The literal operators take as an argument a long double and return a MyDistance object. MyDistance is automatically normalized to meters. And now? That's was the whole functionality that the programmer has to provide.
I totally ignored one big optimization potential in my program. Almost all operations can be performed at compile time; almost all objects can be instantiated at compile time. To make that happen I have to declare the operations and objects as constexpr respectively. I will present this feature in the post constant expression.
What's next?
You can define user-defined literals not only for floating-point numbers. You can do it for integers, characters, and C strings. In addition, C++ has for integers and floating-point numbers two ways to do it. One is called cooked the other raw. I have a lot more to write about user-defined literals. Wait for the next post.
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, and Ann Shatoff.
Thanks in particular to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, and Slavko Radman.
My special thanks to Embarcadero 
My special thanks to PVS-Studio 
My special thanks to Tipi.build 
Seminars
I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.
Bookable (Online)
German
Standard Seminars (English/German)
Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.
- C++ - The Core Language
- C++ - The Standard Library
- C++ - Compact
- C++11 and C++14
- Concurrency with Modern C++
- Design Pattern and Architectural Pattern with C++
- Embedded Programming with Modern C++
- Generic Programming (Templates) with C++
New
- Clean Code with Modern C++
- C++20
Contact Me
- Phone: +49 7472 917441
- Mobil:: +49 176 5506 5086
- Mail: This email address is being protected from spambots. You need JavaScript enabled to view it.
- German Seminar Page: www.ModernesCpp.de
- Mentoring Page: www.ModernesCpp.org
Modernes C++,

Read more...