Strong Typing

Improve Type Safety in Your C++ Program With the type_safe Library

The type_safe library is developed by Jonathan Müller, a C++ library and author of foonathan::blog(). The type_safe library provides zero-overhead utilities to help catch bugs at compile time.

Features provided by the type_safe library include improved built-in types (ts::integer, ts::floating_point, and ts::boolean) which prevent dangerous implicit operations like signed-to-unsigned promotion. The library also provides "vocabulary" types to help us write more expressive code, such as object_ref (non-null ptr), array_ref (reference to an array), and function_ref (reference to a function). Other interesting concepts are also provided, such as deferred_construction, a wrapper which allows you to create an object without constructing.

Similar to NamedType, this library also supports strong types. Where NamedType provides a simple interface for creating strong types, the type_safe library requires explicit declaration of the attributes our strong type supports. The increased overhead for setting up new types is worth the safety provided by explicitly deciding what operations should be allowed. In the example below, our strong type only has addition and subtraction operations enabled:

struct meter
: strong_typedef<meter, int>, addition<meter>, subtraction<meter>
{
    using strong_typedef::strong_typedef;
};

Use the type_safe library to write expressive code and increase the number of errors caught during compilation.

Further Reading

For more on type_safe:

NamedType: The Easy Way to Use Strong Types in C++

NamedType is a library written by Jonathan Boccara, a C++ developer and author of the FluentC++ blog. The NamedType library provides a simple interface for using strong types, which are not natively supported in C++.

We often utilize native types, such as int or double, to represent the values in our software. The general nature of these types means that we can easily make mistakes in our code. Consider a simple rectangle constructor:

Rectangle(double width, double height);

If you swapped the width or height in your code, the compiler would never be able to tell you.

double width = 10.5;
double height = 3.0;
Rectangle r(height, width); // wrong but compiles!

By using strong types in our interfaces, we can make our APIs more explicit and rely on the compiler to catch any mistakes:

// Create our strong types
using Width = NamedType<double, struct WidthTag>;
using Height = NamedType<double, struct HeightTag>;
//…
Rectangle(Width width, Height height); // new constructor
//…
Rectangle r(Height(3.0), Width(10.5)); // compiler error - type mismatch!
Rectangle r2(Width(10.5), Height(3.0)); // ok

The great news is that strong types are zero-cost when compiling with -O2 (or -O1 with GCC). It's time to make your APIs more explicit and catch errors during compilation.

Furher Reading

For more on NamedType and strong types in C++: