Favorite Tools: C++11 User-defined literals
In many software domains units of measurement are frequently critical to the software's data processing requirements. Those same units, or rather the use of the wrong units, are often the source of bugs and disastrous mistakes. Although useful for other purposes, user-defined literals are an excellent addition to the C++11 standard and handy when working with units of measurement.
Suppose a device measures velocity. To help prevent errors, the software specification requires all internal interfaces to use meters per second (m/s) for exchanging velocity data. Although the code itself may properly enforce this restriction, we may find product specifications designating key requirements in kilometers per second, miles per hour, or other units of velocity. Inspecting our device specifications we find the following requirement:
"The device shall emit an alert tone when the velocity exceeds 80 MPH."
The engineer tasked to implement this requirement has various choices. In a C code environment, the engineer might implement a macro that converts miles per hour to meters per second or may simply convert MPH to (m/s) offline and use the converted value directly. Let us see what these might look like:
#define ALERT_TONE_TRIGGER_VELOCITY 35.7632f
or
#define ALERT_TONE_TRIGGER_VELOCITY (MPH_TO_METERS_PER_SECOND(80))
In the first example shown, the value we read in the code no longer directly matches the written specifications, creating a mental hurdle during code reviews and increasing the opportunity for mistakes if and when the specifications are changed. For the second example shown above, it is certainly ok, yet reads backwards. Each of the above examples will work, however, I prefer C++11's new user-defined literal approach. Shown below is the alert trigger value as defined using C++11’s user-defined literal approach:
constexpr MetersPerSecond ALERT_TONE_TRIGGER_VELOCITY = 80_MPH;
Now the code reads the same as the specification.
But how did the "_MPH" user-defined literal actually work? Here is the code creating the new user-defined literal definition:
constexpr MetersPerSecond operator"" _MPH ( long double value ) { return MetersPerSecond(value * 0.44704); } constexpr MetersPerSecond operator"" _MPH ( unsigned long long value ) { return MetersPerSecond(value * 0.44704); }
The code now has the ability to append _MPH to either a constant floating point number or a constant integer and the compiler will convert the value during compilation to our MetersPerSecond type.
The new C++11 user-defined literal approach is type-safe, readable, and in this example, the compiler performs the conversion at compile time. What is not to like? As an error prone human, I want to reduce the odds of creating software errors, and with user-defined literals I now have another tool to draw upon in my error-reducing tool chest.
To learn more about user-defined literals, check out the following useful resources:
http://en.cppreference.com/w/cpp/language/user_lit...
http://arne-mertz.de/2016/10/modern-c-features-use...
And then please let us know if you have made use of the new C++11 user-defined literals and if so, how?
- Comments
- Write a Comment Select to add a comment
FWIW, I recently used the approach described in my post to improve my FreeRTOS usage on an ESP32 based demo project.
Before:
xTimerCreate("Demo", pdMS_TO_TICKS(1000), pdTRUE, nullptr, DemoTimerCallback);
After:
xTimerCreate("Demo", 1000_milliseconds, pdTRUE, nullptr, DemoTimerCallback);
What do you think?
The C++11 compatible header that enables this user defined literal may be seen here:
https://github.com/mattheweshleman/FreeRTOSEsp32Ac...
Enjoy!
To post reply to a comment, click on the 'reply' button attached to each comment. To post a new comment (not a reply to a comment) check out the 'Write a Comment' tab at the top of the comments.
Please login (on the right) if you already have an account on this platform.
Otherwise, please use this form to register (free) an join one of the largest online community for Electrical/Embedded/DSP/FPGA/ML engineers: