-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStrongType.hpp
More file actions
167 lines (155 loc) · 5.15 KB
/
StrongType.hpp
File metadata and controls
167 lines (155 loc) · 5.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#pragma once
#include <iostream>
#include <type_traits>
namespace qip {
template <auto enumV, typename BaseT> struct StrongType {
private:
static_assert(std::is_arithmetic_v<BaseT>,
"StrongType only available for arithmetic types");
static_assert(
std::is_enum_v<decltype(enumV)>,
"StrongType must be instantiated with scoped enum (enum class)");
using StrongT = StrongType<enumV, BaseT>; // type alias
public:
BaseT value;
explicit constexpr StrongType(BaseT tv) : value(tv) {}
explicit constexpr operator BaseT() const { return value; }
constexpr BaseT &as_base() { return value; }
[[nodiscard]] constexpr BaseT as_base() const { return value; }
using BaseType = BaseT; // makes 'BaseType' publicly accessible
//! Provides operators for regular arithmetic operations
constexpr StrongT &operator*=(const StrongT &rhs) {
this->value *= rhs.value;
return *this;
}
friend constexpr StrongT operator*(StrongT lhs, const StrongT &rhs) {
return lhs *= rhs;
}
constexpr StrongT &operator/=(const StrongT &rhs) {
this->value /= rhs.value;
return *this;
}
friend constexpr StrongT operator/(StrongT lhs, const StrongT &rhs) {
return lhs /= rhs;
}
constexpr StrongT &operator+=(const StrongT &rhs) {
this->value += rhs.value;
return *this;
}
friend constexpr StrongT operator+(StrongT lhs, const StrongT &rhs) {
return lhs += rhs;
}
constexpr StrongT &operator-=(const StrongT &rhs) {
this->value -= rhs.value;
return *this;
}
friend constexpr StrongT operator-(StrongT lhs, const StrongT &rhs) {
return lhs -= rhs;
}
//! Provide Base*Strong, Strong*Base oprators - allow scalar multiplication
constexpr StrongT &operator*=(const BaseT &rhs) {
this->value *= rhs;
return *this;
}
friend constexpr StrongT operator*(StrongT lhs, const BaseT &rhs) {
return lhs *= rhs;
}
friend constexpr StrongT operator*(const BaseT &lhs, StrongT rhs) {
return rhs *= lhs;
}
//! Provide Strong/Base, but NOT Base/Strong (still scalar multiplication).
// If StrongT is used for physical units, this will likely not be what you
// want. In this case, just be explicit. Base/Strong is not scalar
// multiplication.
constexpr StrongT &operator/=(const BaseT &rhs) {
this->value /= rhs;
return *this;
}
friend constexpr StrongT operator/(StrongT lhs, const BaseT &rhs) {
return lhs /= rhs;
}
//! Provides pre/post increment/decrement (++, --) operators
constexpr StrongT &operator++() {
++value;
return *this;
}
constexpr StrongT operator++(int) {
StrongT result(*this);
++(*this);
return result;
}
constexpr StrongT &operator--() {
--value;
return *this;
}
constexpr StrongT operator--(int) {
StrongT result(*this);
--(*this);
return result;
}
//! Provides comparison operators
friend constexpr bool operator==(const StrongT &lhs, const StrongT &rhs) {
return lhs.value == rhs.value;
}
friend constexpr bool operator!=(const StrongT &lhs, const StrongT &rhs) {
return !(lhs == rhs);
}
friend constexpr bool operator<(const StrongT &lhs, const StrongT &rhs) {
return lhs.value < rhs.value;
}
friend constexpr bool operator>(const StrongT &lhs, const StrongT &rhs) {
return rhs < lhs;
}
friend constexpr bool operator<=(const StrongT &lhs, const StrongT &rhs) {
return !(rhs < lhs);
}
friend constexpr bool operator>=(const StrongT &lhs, const StrongT &rhs) {
return !(lhs < rhs);
}
//! Provides operators for direct comparison w/ BaseT literal (rvalue).
//! Note: Does not allow comparison with BaseT lvalue
friend constexpr bool operator==(const StrongT &lhs, const BaseT &&rhs) {
return lhs.value == rhs;
}
friend constexpr bool operator!=(const StrongT &lhs, const BaseT &&rhs) {
return lhs.value != rhs;
}
friend constexpr bool operator<(const StrongT &lhs, const BaseT &&rhs) {
return lhs.value < rhs;
}
friend constexpr bool operator>(const StrongT &lhs, const BaseT &&rhs) {
return lhs.value > rhs;
}
friend constexpr bool operator<=(const StrongT &lhs, const BaseT &&rhs) {
return lhs.value <= rhs;
}
friend constexpr bool operator>=(const StrongT &lhs, const BaseT &&rhs) {
return lhs.value >= rhs;
}
friend constexpr bool operator==(const BaseT &&lhs, const StrongT &rhs) {
return lhs == rhs.value;
}
friend constexpr bool operator!=(const BaseT &&lhs, const StrongT &rhs) {
return lhs != rhs.value;
}
friend constexpr bool operator<(const BaseT &&lhs, const StrongT &rhs) {
return lhs < rhs.value;
}
friend constexpr bool operator>(const BaseT &&lhs, const StrongT &rhs) {
return lhs > rhs.value;
}
friend constexpr bool operator<=(const BaseT &&lhs, const StrongT &rhs) {
return lhs <= rhs.value;
}
friend constexpr bool operator>=(const BaseT &&lhs, const StrongT &rhs) {
return lhs >= rhs.value;
}
//! Provides iostream interface, works as it would for BaseT
friend std::ostream &operator<<(std::ostream &os, const StrongT &rhs) {
return os << rhs.value;
}
friend std::istream &operator>>(std::istream &is, StrongT &rhs) {
return is >> rhs.value;
}
};
} // namespace qip