C++ features: User-defined literals

Published Feb 26, 2017Last updated Feb 28, 2017
C++ features: User-defined literals

In this post we will firstly talk about the importance, capabilities and restrictions of user-defined literals. Then we will learn how to implement user-defined literals in C++.
The very first version of C++ having the support for user-defined literals was C++11 and that are basically built-in type constants with some suffix defined by the programmer. Supported compilers for such kind of literals are GCC 4.7, Clang 3.1 etc with only few built-in types compatible. With the release of C++14 support for <chrono> and <string> were also involved to support user-defined literals (in the compiler GCC 5.0). It is recommended to have at least one of these compiler configured in your system before going further with the article.

Built-in literals

Built-in literals, are used to set values to built-in data types, and have constants that we know at the compile-time.

unsigned int uint = 25U; // for unsigned integer with value 25 
auto i = 0x30;           // set decimal value 48 to i

In the above examples 25U and 0x30 are built-in literals to set the values of built-in types unsigned int and an integer respectively.

User-defined literals

In C++11, we can only define user-defined literals with some built-in types only such as integral numbers, floating point numbers, characters and character arrays. Different literals can be defined by using different suffixes after the built-in constants. Basic importance of these literals in the language is to provide some mechanism to create some new literal types using predefined libraries rather than by changing the core part of the language. The other use of such literals was to prepare the way for addition of some new components to C++ Standard libraries e.g. new string type, SI units etc.

There are number of ways to define a literal suffix. In this article we only focus ourself to a type called cooked literal. We here take an example of a case where we need to measure some physical quantity like height. Since there are many units to use for incorporating height in our program so we need to make a new type 'meters'. Rather than using double type for height, we will use this new type as a standard unit.

class Meters
  double mts;

  class PreventUsage{};
    explicit constexpr Meters(PreventUsage, double meter) : mts{meter} {}

Meters mt = 23; // This will give us compile-time error

In the above code segment, the constructor we defined will prevent assigning the double value directly to the newly created class object. Here, we can achieve this assignment by following syntax:

Meters mt = 23_m;

We should define such literal suffixes with starting underscore due to the limitations of C++. Using this convention prevents any clash between standard suffixes and user-defined suffixes. Our literal for above exmaple will be defined as below:

constexpr Meters operator "" _m(long double mt){
  return Meters{Meters::PreventUsage{}, static_cast<double> mt};

Here, we have defined a special kind of operator which takes a long double and returns Meters type. This operator "" _m is convention to define a literal suffix _m with a space between "" and _m. Similarly, we can define other literal suffixes e.g. _in(for inches), _ft (for feet) etc to include other units that can be converted and saved in the form of Meters type.

constexpr Meters operator "" _in(long double in){
  return Meters{Meters::PreventUsage{}, static_cast<double> (in * 0.0254)};

You can notice here in our definition of operator that we took long double as parameter while we needed to store a double type in Meters. This is because of literal definitions that gives us only a fixed number of parameters we can pass through this operator. Those fixed types are: const char *, unsigned long long int, long double, char, wchar_t, char16_t, char32_t in C++11.

For further reading

You can read C++ Standards Committee paper about user-defined literals for further reading.

Feel free to comment if you have doubts!!
Thanks for reading.

Discover and read more posts from DUSHYANT KUMAR
get started