Jonathan Boccara's blog

A Recap on User Defined Literals

Published October 8, 2021 - 0 Comments

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.

C++11: Introduction of user defined literals

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 defined operator"" to create this type the following way:

MyType operator""_myType(unsigned long long int value)
{
    return MyType{value};
}

This allows 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 "".

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 integers (as in our above example)
  • long double to represent floating point numbers
  • char to represent individual characters
  • const char* to represent strings
  • const char*, size_t size to represent strings

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
{
    // ...
}

Evolutions in C++14 and C++17

C++11 introduced the technology of user defined literals, but didn’t provide any user defined suffix in the standard library. Those come in C++14 and C++17.

There are three types of literals provided by the standard library: string literals (C++14), chrono literals (C++14) and string view literals (C++17).

String literals

There is one user defined literal for strings in the standard library: s. Note that it doesn’t have an underscore since it is provided by the standard library.

s is in the std::literals::string_literals namespace. You can use it this way:

using namespace std::literals::string_literals;

auto myString = "hello"s;

In this code, myString is of type std::string. Compare this to the following code:

auto myString = "hello";

In that case, myString is of type const char*.

Chrono literals

The part of the standard library that provides the most user defined suffixes is chrono, the part of the standard library dealing with date and times utilities.

In particular, chrono offers literals for all the typical units of duration: minutes, second, hours, etc:

using namespace std::literals::chrono_literals;

auto threeSeconds = 3s;
auto tenMinutes = 10min;
auto twoHours = 2h;

auto oneMillisecond = 1ms;
auto oneMicroSecond = 1us;
auto oneNanoSecond = 1ns;

String view literals

Finally, the user defined suffix that C++17 added is sv, in the std::literals::string_view_literals namespace. sv allows to create an std::string_view:

using namespace std::literals::string_view_literals;

auto myStringView = "hello"sv;

In this above code, myStringView is of type std::string_view.

Usages 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.

However, user defined literals can also have other usages! How do you use user literals in your code? I’d love to read your story in a comment below.

You will also like

Don't want to miss out ? Follow:   twitterlinkedinrss
Share this post!Facebooktwitterlinkedin