Named Types in C++
A strong type or named type is a type used in place of another type to carry specific meaning through its name.
Its central piece is the templated class NamedType, which can be used to declare a strong type with a typedef-like syntax:
using Width = NamedType<double, struct WidthTag>; using Height = NamedType<double, struct HeightTag>;
which can be used to make interfaces more expressive and more robust. Note how the below constructor shows in which order it expects its parameters:
class Rectangle
{
public:
Rectangle(Width w, Height h) : width(w.get()), height(h.get()) {}
// ...
private:
double width;
double height;
};
Implemention
This is how you can write a class:
struct Default_NamedType_tag {};
template <typename T, typename TAG = Default_NamedType_tag>
class NamedType
{
public:
explicit NamedType(T const& value) : value_(value) {}
explicit NamedType(T&& value) : value_(std::move(value)) {}
T& get() { return value_; }
T const& get() const {return value_; }
private:
T value_;
};
Strong typing over generic types
This implementation of strong types can be used to add strong typing over generic or unknown types such as lambdas:
template<typename Function>
using Comparator = NamedType<Function, struct ComparatorTag>;
template <typename Function>
void performAction(Comparator<Function> comp)
{
comp.get()();
}
performAction(make_named<Comparator>([](){ std::cout << "compare\n"; }));
Strong typing over references
The NamedType class is designed so that the following usage:
using FamilyNameRef = NamedType<std:string&, struct FamilyNameRefTag>;
behaves like a reference on an std::string, strongly typed.
Named arguments
By their nature strong types can play the role of named parameters:
using FirstName = NamedType<std::string, struct FirstNameTag>;
using LastName = NamedType<std::string, struct LastNameTag>;
void displayName(FirstName const& theFirstName, LastName const& theLastName);
// Call site
displayName(FirstName("John"), LastName("Doe"));
But the nested type argument allows to emulate a named argument syntax:
using FirstName = NamedType<std::string, struct FirstNameTag>; using LastName = NamedType<std::string, struct LastNameTag>; static const FirstName::argument firstName; static const LastName::argument lastName; void displayName(FirstName const& theFirstName, LastName const& theLastName); // Call site displayName(firstName = "John", lastName = "Doe");