ampsci
c++ program for high-precision atomic structure calculations of single-valence systems
StrongType.hpp
1 #pragma once
2 #include <iostream>
3 #include <type_traits>
4 
6 namespace qip {
7 
44 template <auto enumV, typename BaseT>
45 struct StrongType {
46 private:
47  static_assert(std::is_arithmetic_v<BaseT>,
48  "StrongType only available for arithmetic types");
49  static_assert(
50  std::is_enum_v<decltype(enumV)>,
51  "StrongType must be instantiated with scoped enum (enum class)");
52  using StrongT = StrongType<enumV, BaseT>; // type alias
53 
54 public:
55  BaseT v;
56 
57  explicit constexpr StrongType(BaseT tv) : v(tv) {}
58  explicit constexpr operator BaseT() const { return v; }
59  constexpr BaseT &as_base() { return v; }
60  [[nodiscard]] constexpr BaseT as_base() const { return v; }
61 
63  using BaseType = BaseT;
64 
66  constexpr StrongT &operator*=(const StrongT &rhs) {
67  this->v *= rhs.v;
68  return *this;
69  }
70  friend constexpr StrongT operator*(StrongT lhs, const StrongT &rhs) {
71  return lhs *= rhs;
72  }
73  constexpr StrongT &operator/=(const StrongT &rhs) {
74  this->v /= rhs.v;
75  return *this;
76  }
77  friend constexpr StrongT operator/(StrongT lhs, const StrongT &rhs) {
78  return lhs /= rhs;
79  }
80  constexpr StrongT &operator+=(const StrongT &rhs) {
81  this->v += rhs.v;
82  return *this;
83  }
84  friend constexpr StrongT operator+(StrongT lhs, const StrongT &rhs) {
85  return lhs += rhs;
86  }
87  constexpr StrongT &operator-=(const StrongT &rhs) {
88  this->v -= rhs.v;
89  return *this;
90  }
91  friend constexpr StrongT operator-(StrongT lhs, const StrongT &rhs) {
92  return lhs -= rhs;
93  }
94 
96  constexpr StrongT &operator*=(const BaseT &rhs) {
97  this->v *= rhs;
98  return *this;
99  }
100  friend constexpr StrongT operator*(StrongT lhs, const BaseT &rhs) {
101  return lhs *= rhs;
102  }
103  friend constexpr StrongT operator*(const BaseT &lhs, StrongT rhs) {
104  return rhs *= lhs;
105  }
107  // If StrongT is used for physical units, this will likely not be what you
108  // want. In this case, just be explicit. Base/Strong is not scalar
109  // multiplication.
110  constexpr StrongT &operator/=(const BaseT &rhs) {
111  this->v /= rhs;
112  return *this;
113  }
114  friend constexpr StrongT operator/(StrongT lhs, const BaseT &rhs) {
115  return lhs /= rhs;
116  }
117 
119  constexpr StrongT &operator++() {
120  ++v;
121  return *this;
122  }
123  constexpr StrongT operator++(int) {
124  StrongT result(*this);
125  ++(*this);
126  return result;
127  }
128  constexpr StrongT &operator--() {
129  --v;
130  return *this;
131  }
132  constexpr StrongT operator--(int) {
133  StrongT result(*this);
134  --(*this);
135  return result;
136  }
137 
139  friend constexpr bool operator==(const StrongT &lhs, const StrongT &rhs) {
140  return lhs.v == rhs.v;
141  }
142  friend constexpr bool operator!=(const StrongT &lhs, const StrongT &rhs) {
143  return !(lhs == rhs);
144  }
145  friend constexpr bool operator<(const StrongT &lhs, const StrongT &rhs) {
146  return lhs.v < rhs.v;
147  }
148  friend constexpr bool operator>(const StrongT &lhs, const StrongT &rhs) {
149  return rhs < lhs;
150  }
151  friend constexpr bool operator<=(const StrongT &lhs, const StrongT &rhs) {
152  return !(rhs < lhs);
153  }
154  friend constexpr bool operator>=(const StrongT &lhs, const StrongT &rhs) {
155  return !(lhs < rhs);
156  }
157 
160  friend constexpr bool operator==(const StrongT &lhs, const BaseT &&rhs) {
161  return lhs.v == rhs;
162  }
163  friend constexpr bool operator!=(const StrongT &lhs, const BaseT &&rhs) {
164  return lhs.v != rhs;
165  }
166  friend constexpr bool operator<(const StrongT &lhs, const BaseT &&rhs) {
167  return lhs.v < rhs;
168  }
169  friend constexpr bool operator>(const StrongT &lhs, const BaseT &&rhs) {
170  return lhs.v > rhs;
171  }
172  friend constexpr bool operator<=(const StrongT &lhs, const BaseT &&rhs) {
173  return lhs.v <= rhs;
174  }
175  friend constexpr bool operator>=(const StrongT &lhs, const BaseT &&rhs) {
176  return lhs.v >= rhs;
177  }
178  friend constexpr bool operator==(const BaseT &&lhs, const StrongT &rhs) {
179  return lhs == rhs.v;
180  }
181  friend constexpr bool operator!=(const BaseT &&lhs, const StrongT &rhs) {
182  return lhs != rhs.v;
183  }
184  friend constexpr bool operator<(const BaseT &&lhs, const StrongT &rhs) {
185  return lhs < rhs.v;
186  }
187  friend constexpr bool operator>(const BaseT &&lhs, const StrongT &rhs) {
188  return lhs > rhs.v;
189  }
190  friend constexpr bool operator<=(const BaseT &&lhs, const StrongT &rhs) {
191  return lhs <= rhs.v;
192  }
193  friend constexpr bool operator>=(const BaseT &&lhs, const StrongT &rhs) {
194  return lhs >= rhs.v;
195  }
196 
198  friend std::ostream &operator<<(std::ostream &os, const StrongT &rhs) {
199  return os << rhs.v;
200  }
201  friend std::istream &operator>>(std::istream &is, StrongT &rhs) {
202  return is >> rhs.v;
203  }
204 };
205 
206 } // namespace qip
qip library: A collection of useful functions
Definition: Array.hpp:8
A light-weight easy-to-use single-file header-only template class for strong typing.
Definition: StrongType.hpp:45
constexpr friend bool operator==(const StrongT &lhs, const StrongT &rhs)
Provides comparison operators.
Definition: StrongType.hpp:139
constexpr StrongT & operator*=(const StrongT &rhs)
Provides operators for regular arithmetic operations.
Definition: StrongType.hpp:66
friend std::ostream & operator<<(std::ostream &os, const StrongT &rhs)
Provides iostream interface, works as it would for BaseT.
Definition: StrongType.hpp:198
constexpr friend bool operator==(const StrongT &lhs, const BaseT &&rhs)
Provides operators for direct comparison w/ BaseT literal (rvalue). Note: Does not allow comparison w...
Definition: StrongType.hpp:160
constexpr StrongT & operator*=(const BaseT &rhs)
Provide Base*Strong, Strong*Base oprators - allow scalar multiplication.
Definition: StrongType.hpp:96
constexpr StrongT & operator++()
Provides pre/post increment/decrement (++, –) operators.
Definition: StrongType.hpp:119
constexpr StrongT & operator/=(const BaseT &rhs)
Provide Strong/Base, but NOT Base/Strong (still scalar multiplication).
Definition: StrongType.hpp:110
BaseT BaseType
makes 'BaseType' publicly accessible
Definition: StrongType.hpp:63