| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | // [Getting the Benefits of Strong Typing in C++ at a Fraction of the Cost](https://www.fluentcpp.com/2018/04/06/strong-types-by-struct/) | ||
| 4 | |||
| 5 | // A simple strong type using inheritance. | ||
| 6 | // Example until C++17: struct MyInt : StrongType<int> { using base::base; }; | ||
| 7 | // Example since C++17: struct MyInt : StrongType<int> { }; | ||
| 8 | template <typename T> | ||
| 9 | struct StrongType { | ||
| 10 | using type = T; // underlying type | ||
| 11 | T value{}; // zero-initialized value | ||
| 12 | #if __cplusplus < 201703L // until C++17 | ||
| 13 | // Provide an explicit constructor that can be inherited because | ||
| 14 | // [aggregate initialization](https://en.cppreference.com/w/cpp/language/aggregate_initialization) | ||
| 15 | // cannot be used with derived types until C++17. | ||
| 16 | using base = StrongType; // base type | ||
| 17 | explicit StrongType(T v) : value{v} {}; // constructor | ||
| 18 | StrongType() noexcept = default; // default constructor | ||
| 19 | StrongType(const StrongType&) = default; // copy constructor | ||
| 20 | StrongType(StrongType&&) noexcept = default; // move constructor | ||
| 21 | StrongType& operator=(const StrongType&) = default; // copy assignment | ||
| 22 | StrongType& operator=(StrongType&&) noexcept = default; // move assignment | ||
| 23 | ~StrongType() noexcept = default; // CAUTION: non-virtual destructor | ||
| 24 | #endif // C++17 | ||
| 25 | }; | ||
| 26 | |||
| 27 | // A simple strong identifier using inheritance. | ||
| 28 | // Example until C++17: struct MyId : StrongIdentifier<int> { using base::base; }; | ||
| 29 | // Example since C++17: struct MyId : StrongIdentifier<int> { }; | ||
| 30 | template <typename T> | ||
| 31 | struct StrongIdentifier : StrongType<T> { | ||
| 32 | const static StrongIdentifier null; // initialized later | ||
| 33 | bool operator==(StrongIdentifier other) const noexcept; // equal | ||
| 34 | bool operator<(StrongIdentifier other) const noexcept; // less | ||
| 35 | #if __cplusplus < 201703L // until C++17 | ||
| 36 | using base = StrongIdentifier; // base type | ||
| 37 | using StrongType<T>::StrongType; // inherit constructors | ||
| 38 | #endif // C++17 | ||
| 39 | }; | ||
| 40 | |||
| 41 | template <typename T> | ||
| 42 | const StrongIdentifier<T> StrongIdentifier<T>::null{}; // zero-initialized | ||
| 43 | |||
| 44 | template <typename T> | ||
| 45 | 3 | bool StrongIdentifier<T>::operator==(StrongIdentifier other) const noexcept { | |
| 46 | 3 | return this->value == other.value; | |
| 47 | } | ||
| 48 | |||
| 49 | template <typename T> | ||
| 50 | bool StrongIdentifier<T>::operator<(StrongIdentifier other) const noexcept { | ||
| 51 | return this->value < other.value; | ||
| 52 | } | ||
| 53 |