Skip to content

Commit 5bf0091

Browse files
author
Colin Robertson
authored
Fix 1963 error in UDL example (#2718)
1 parent 865d6f8 commit 5bf0091

File tree

1 file changed

+30
-18
lines changed

1 file changed

+30
-18
lines changed

docs/cpp/user-defined-literals-cpp.md

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
---
22
title: "User-defined literals (C++)"
3-
ms.date: "12/10/2019"
3+
description: "Describes the purpose and use of user-defined literals in Standard C++."
4+
ms.date: "02/10/2020"
45
ms.assetid: ff4a5bec-f795-4705-a2c0-53788fd57609
56
---
67
# User-defined literals
78

8-
There are five major categories of literals in C++: integer, character, floating-point, string, boolean and pointer. Starting in C++ 11 you can define your own literals based on these categories to provide syntactic shortcuts for common idioms and increase type safety. For example, let's say you have a Distance class. You could define a literal for kilometers and another one for miles, and encourage the user to be explicit about the units of measure by simply writing: auto d = 42.0_km or auto d = 42.0_mi. There is no performance advantage or disadvantage to user-defined literals; they are primarily for convenience or for compile-time type deduction. The Standard Library has user-defined literals for std:string, for std::complex, and for units in time and duration operations in the \<chrono> header:
9+
There are six major categories of literals in C++: integer, character, floating-point, string, boolean, and pointer. Starting in C++ 11, you can define your own literals based on these categories, to provide syntactic shortcuts for common idioms and increase type safety. For example, let's say you have a `Distance` class. You could define a literal for kilometers and another one for miles, and encourage the user to be explicit about the units of measure by writing: `auto d = 42.0_km` or `auto d = 42.0_mi`. There's no performance advantage or disadvantage to user-defined literals; they're primarily for convenience or for compile-time type deduction. The Standard Library has user-defined literals for `std::string`, for `std::complex`, and for units in time and duration operations in the \<chrono> header:
910

1011
```cpp
1112
Distance d = 36.0_mi + 42.0_km; // Custom UDL (see below)
@@ -34,74 +35,85 @@ ReturnType operator "" _r(const char*); // Raw literal operator
3435
template<char...> ReturnType operator "" _t(); // Literal operator template
3536
```
3637

37-
The operator names in the previous example are placeholders for whatever name you provide; however, the leading underscore is required. (Only the Standard Library is allowed to define literals without the underscore.) The return type is where you customize the conversion or other operation that the literal performs. Also, any of these operators can be defined as `constexpr`.
38+
The operator names in the previous example are placeholders for whatever name you provide; however, the leading underscore is required. (Only the Standard Library is allowed to define literals without the underscore.) The return type is where you customize the conversion or other operations done by the literal. Also, any of these operators can be defined as `constexpr`.
3839

3940
## Cooked literals
4041

41-
In source code any literal whether user-defined or not is essentially a sequence of alphanumeric characters, such as `101`, or `54.7`, or `"hello"` or `true`. The compiler interprets the sequence as an integer, float, const char\* string, and so on. A user-defined literal that accepts as input whatever type the compiler assigned to the literal value is informally known as a *cooked literal*. All the operators above except `_r` and `_t` are cooked literals. For example, a literal `42.0_km` would bind to an operator named _km that had a signature similar to _b and the literal `42_km` would bind to an operator with a signature similar to _a.
42+
In source code, any literal, whether user-defined or not, is essentially a sequence of alphanumeric characters, such as `101`, or `54.7`, or `"hello"` or `true`. The compiler interprets the sequence as an integer, float, const char\* string, and so on. A user-defined literal that accepts as input whatever type the compiler assigned to the literal value is informally known as a *cooked literal*. All the operators above except `_r` and `_t` are cooked literals. For example, a literal `42.0_km` would bind to an operator named _km that had a signature similar to _b and the literal `42_km` would bind to an operator with a signature similar to _a.
4243

43-
The following example shows how user-defined literals can encourage callers to be explicit about their input. To construct a `Distance`, the user must explicitly specify kilometers or miles by using the appropriate user-defined literal. Of course you can also achieve the same result in other ways, but user-defined literals are less verbose than the alternatives.
44+
The following example shows how user-defined literals can encourage callers to be explicit about their input. To construct a `Distance`, the user must explicitly specify kilometers or miles by using the appropriate user-defined literal. You can achieve the same result in other ways, but user-defined literals are less verbose than the alternatives.
4445

4546
```cpp
47+
// UDL_Distance.cpp
48+
49+
#include <iostream>
50+
#include <string>
51+
4652
struct Distance
4753
{
4854
private:
4955
explicit Distance(long double val) : kilometers(val)
5056
{}
5157

52-
friend Distance operator"" _km(long double val);
58+
friend Distance operator"" _km(long double val);
5359
friend Distance operator"" _mi(long double val);
60+
5461
long double kilometers{ 0 };
5562
public:
63+
const static long double km_per_mile;
5664
long double get_kilometers() { return kilometers; }
57-
Distance operator+(Distance& other)
65+
66+
Distance operator+(Distance other)
5867
{
5968
return Distance(get_kilometers() + other.get_kilometers());
6069
}
6170
};
6271

63-
Distance operator"" _km(long double val)
72+
const long double Distance::km_per_mile = 1.609344L;
73+
74+
Distance operator"" _km(long double val)
6475
{
6576
return Distance(val);
6677
}
6778

6879
Distance operator"" _mi(long double val)
6980
{
70-
return Distance(val * 1.6);
81+
return Distance(val * Distance::km_per_mile);
7182
}
72-
int main(int argc, char* argv[])
83+
84+
int main()
7385
{
7486
// Must have a decimal point to bind to the operator we defined!
7587
Distance d{ 402.0_km }; // construct using kilometers
76-
cout << "Kilometers in d: " << d.get_kilometers() << endl; // 402
88+
std::cout << "Kilometers in d: " << d.get_kilometers() << std::endl; // 402
7789

7890
Distance d2{ 402.0_mi }; // construct using miles
79-
cout << "Kilometers in d2: " << d2.get_kilometers() << endl; //643.2
91+
std::cout << "Kilometers in d2: " << d2.get_kilometers() << std::endl; //646.956
8092

8193
// add distances constructed with different units
8294
Distance d3 = 36.0_mi + 42.0_km;
83-
cout << "d3 value = " << d3.get_kilometers() << endl; // 99.6
95+
std::cout << "d3 value = " << d3.get_kilometers() << std::endl; // 99.9364
8496

8597
// Distance d4(90.0); // error constructor not accessible
8698

87-
string s;
88-
getline(cin, s);
99+
std::string s;
100+
std::getline(std::cin, s);
89101
return 0;
90102
}
91103
```
92104

93-
Note that the literal number must use a decimal, otherwise the number would be interpreted as an integer and the type would not be compatible with the operator. Also note that for floating point input, the type must be **long double**, and for integral types it must be **long long**.
105+
The literal number must use a decimal. Otherwise, the number would be interpreted as an integer, and the type wouldn't be compatible with the operator. For floating point input, the type must be **long double**, and for integral types it must be **long long**.
94106

95107
## Raw literals
96108

97-
In a raw user-defined literal, the operator that you define accepts the literal as a sequence of char values and it is up to you to interpret that sequence as a number or string or other type. In the list of operators shown earlier in this page, `_r` and `_t` can be used to define raw literals:
109+
In a raw user-defined literal, the operator that you define accepts the literal as a sequence of char values. It's up to you to interpret that sequence as a number or string or other type. In the list of operators shown earlier in this page, `_r` and `_t` can be used to define raw literals:
98110

99111
```cpp
100112
ReturnType operator "" _r(const char*); // Raw literal operator
101113
template<char...> ReturnType operator "" _t(); // Literal operator template
102114
```
103115

104-
You can use raw literals to provide a custom interpretation of an input sequence that is different than what the compiler would perform. For example, you could define a literal that converts the sequence `4.75987` into a custom Decimal type instead of an IEEE 754 floating point type. Raw literals, like cooked literals, can also be used to perform compile-time validation of input sequences.
116+
You can use raw literals to provide a custom interpretation of an input sequence that's different than the compiler's normal behavior. For example, you could define a literal that converts the sequence `4.75987` into a custom Decimal type instead of an IEEE 754 floating point type. Raw literals, like cooked literals, can also be used for compile-time validation of input sequences.
105117

106118
### Example: Limitations of raw literals
107119

0 commit comments

Comments
 (0)