17 class bad_nullable_access :
public std::runtime_error
21 : std::runtime_error(
"nullable object doesn't have a value") { }
27 template <
typename T,
typename = std::enable_if_t<!std::is_po
inter_v<T>>>
32 : m_dummy{ }, m_hasValue(
false) { }
35 : m_value(std::move(value)), m_hasValue(
true) { }
38 : m_dummy{ }, m_hasValue(
false) { }
45 new(&m_value)T(value.m_value);
66 m_value = value.m_value;
78 new(&m_value)T(value.m_value);
90 m_value = std::move(value);
94 new(&m_value)T(std::move(value));
108 m_value = std::move(value);
112 new(&m_value)T(std::move(value));
128 operator nullable<const T&>()
const
131 return nullable<const T&>(m_value);
136 const T& value()
const
139 throw bad_nullable_access();
144 bool has_value()
const {
return m_hasValue; }
145 const T* operator->()
const {
return &m_value; }
146 const T& operator*()
const {
return m_value; }
147 operator const T* ()
const
156 template <
typename T2>
157 friend bool operator==(
const nullable<T2>& lhs,
const nullable<T2>& rhs);
159 template <
typename T2>
160 friend bool operator!=(
const nullable<T2>& lhs,
const nullable<T2>& rhs);
162 template <
typename T2>
163 friend bool operator==(
const nullable<std::decay_t<T2>>& lhs,
const nullable<T2&>& rhs);
165 template <
typename T2>
166 friend bool operator!=(
const nullable<std::decay_t<T2>>& lhs,
const nullable<T2&>& rhs);
168 template <
typename T2>
169 friend bool operator==(
const nullable<T2&>& lhs,
const nullable<std::decay_t<T2>>& rhs);
171 template <
typename T2>
172 friend bool operator!=(
const nullable<T2&>& lhs,
const nullable<std::decay_t<T2>>& rhs);
174 template <
typename T2>
175 friend bool operator==(
const nullable<T2>& lhs,
const T2& rhs);
177 template <
typename T2>
178 friend bool operator==(
const T2& lhs,
const nullable<T2>& rhs);
180 template <
typename T2>
181 friend bool operator!=(
const nullable<T2>& lhs,
const T2& rhs);
183 template <
typename T2>
184 friend bool operator!=(
const T2& lhs,
const nullable<T2>& rhs);
186 template <
typename T2>
187 friend std::enable_if_t<!std::is_reference_v<T2>,
bool> operator==(
const nullable<T2>& lhs, std::nullptr_t);
189 template <
typename T2>
190 friend std::enable_if_t<!std::is_reference_v<T2>,
bool> operator==(std::nullptr_t,
const nullable<T2>& rhs);
192 template <
typename T2>
193 friend std::enable_if_t<!std::is_reference_v<T2>,
bool> operator!=(
const nullable<T2>& lhs, std::nullptr_t);
195 template <
typename T2>
196 friend std::enable_if_t<!std::is_reference_v<T2>,
bool> operator!=(std::nullptr_t,
const nullable<T2>& rhs);
199 struct NonTrivialDummyType
201 constexpr NonTrivialDummyType() noexcept
210 NonTrivialDummyType m_dummy;
217 template <
typename TRef>
218 class nullable<TRef, std::enable_if_t<std::is_reference_v<TRef>>> final
220 using T = std::remove_reference_t<TRef>;
226 : m_value(&value) { }
231 nullable(std::nullptr_t)
235 template <
typename T2,
typename = std::enable_if_t<
236 std::is_convertible_v<std::add_pointer_t<std::remove_reference_t<T2>>,
237 std::add_pointer_t<std::remove_reference_t<T>>>,
int>>
238 nullable(
const nullable<T2&>& value)
239 : m_value(reinterpret_cast<const nullable&>(value).m_value) { }
241 nullable(
const nullable& value) =
default;
243 nullable& operator=(
const nullable& value) =
default;
247 if (m_value ==
nullptr)
248 throw bad_nullable_access();
253 bool has_value()
const {
return m_value !=
nullptr; }
255 explicit operator T* ()
const {
return m_value; }
256 T* operator->()
const {
return m_value; }
257 T& operator*()
const {
return *m_value; }
260 template <
typename T2>
261 friend bool operator==(
const nullable<std::decay_t<T2>>& lhs,
const nullable<T2&>& rhs);
263 template <
typename T2>
264 friend bool operator==(
const nullable<T2&>& lhs,
const nullable<std::decay_t<T2>>& rhs);
266 template <
typename T2>
267 friend bool operator!=(
const nullable<std::decay_t<T2>>& lhs,
const nullable<T2&>& rhs);
269 template <
typename T2>
270 friend bool operator!=(
const nullable<T2&>& lhs,
const nullable<std::decay_t<T2>>& rhs);
272 template <
typename T2>
273 friend bool operator==(
const nullable<T2&>& lhs,
const nullable<T2&>& rhs);
275 template <
typename T2>
276 friend bool operator==(
const nullable<T2&>& lhs,
const std::decay_t<T2>& rhs);
278 template <
typename T2>
279 friend bool operator==(
const std::decay_t<T2>& lhs,
const nullable<T2&>& rhs);
281 template <
typename T2>
282 friend bool operator!=(
const nullable<T2&>& lhs,
const nullable<T2&>& rhs);
284 template <
typename T2>
285 friend bool operator!=(
const nullable<T2&>& lhs,
const std::decay_t<T2>& rhs);
287 template <
typename T2>
288 friend bool operator!=(
const std::decay_t<T2>& lhs,
const nullable<T2&>& rhs);
290 template <
typename T2>
291 friend std::enable_if_t<std::is_reference_v<T2>,
bool> operator==(
const nullable<T2>& lhs, std::nullptr_t);
293 template <
typename T2>
294 friend std::enable_if_t<std::is_reference_v<T2>,
bool> operator==(std::nullptr_t,
const nullable<T2>& rhs);
296 template <
typename T2>
297 friend std::enable_if_t<std::is_reference_v<T2>,
bool> operator!=(
const nullable<T2>& lhs, std::nullptr_t);
299 template <
typename T2>
300 friend std::enable_if_t<std::is_reference_v<T2>,
bool> operator!=(std::nullptr_t,
const nullable<T2>& rhs);
302 template <
typename T2>
303 friend bool operator==(
const nullable<T2&>& lhs,
const T2* rhs);
305 template <
typename T2>
306 friend bool operator==(
const T2* lhs,
const nullable<T2&>& rhs);
308 template <
typename T2>
309 friend bool operator!=(
const nullable<T2&>& lhs,
const T2* rhs);
311 template <
typename T2>
312 friend bool operator!=(
const T2* lhs,
const nullable<T2&>& rhs);
318 template <
typename T2>
319 bool operator==(
const nullable<T2>& lhs,
const nullable<T2>& rhs)
321 if (lhs.m_hasValue != rhs.m_hasValue)
325 return lhs.m_value == rhs.m_value;
330 template <
typename T2>
331 bool operator!=(
const nullable<T2>& lhs,
const nullable<T2>& rhs)
333 if (lhs.m_hasValue != rhs.m_hasValue)
337 return lhs.m_value != rhs.m_value;
342 template <
typename T2>
343 bool operator==(
const nullable<std::decay_t<T2>>& lhs,
const nullable<T2&>& rhs)
345 if (lhs.m_hasValue != rhs.has_value())
349 return lhs.m_value == *rhs.m_value;
354 template <
typename T2>
355 bool operator!=(
const nullable<std::decay_t<T2>>& lhs,
const nullable<T2&>& rhs)
357 if (lhs.m_hasValue != rhs.has_value())
361 return lhs.m_value != *rhs.m_value;
366 template <
typename T2>
367 bool operator==(
const nullable<T2&>& lhs,
const nullable<std::decay_t<T2>>& rhs)
369 if (lhs.has_value() != rhs.m_hasValue)
373 return *lhs.m_value == rhs.m_value;
378 template <
typename T2>
379 bool operator!=(
const nullable<T2&>& lhs,
const nullable<std::decay_t<T2>>& rhs)
381 if (lhs.has_value() != rhs.m_hasValue)
385 return *lhs.m_value != rhs.m_value;
390 template <
typename T2>
391 bool operator==(
const nullable<T2&>& lhs,
const nullable<T2&>& rhs)
393 if (lhs.has_value() != rhs.has_value())
397 return *lhs.m_value == *rhs.m_value;
402 template <
typename T2>
403 bool operator!=(
const nullable<T2&>& lhs,
const nullable<T2&>& rhs)
405 if (lhs.has_value() != rhs.has_value())
409 return *lhs.m_value != *rhs.m_value;
414 template <
typename T2>
415 bool operator==(
const nullable<T2&>& lhs,
const std::decay_t<T2>& rhs)
417 if (!lhs.has_value())
420 return *lhs.m_value == rhs;
423 template <
typename T2>
424 bool operator!=(
const nullable<T2&>& lhs,
const std::decay_t<T2>& rhs)
426 if (!lhs.has_value())
429 return *lhs.m_value != rhs;
432 template <
typename T2>
433 bool operator==(
const std::decay_t<T2>& lhs,
const nullable<T2&>& rhs)
435 if (!rhs.has_value())
438 return lhs == *rhs.m_value;
441 template <
typename T2>
442 bool operator!=(
const std::decay_t<T2>& lhs,
const nullable<T2&>& rhs)
444 if (!rhs.has_value())
447 return lhs != *rhs.m_value;
450 template <
typename T2>
451 bool operator==(
const nullable<T2>& lhs,
const T2& rhs)
456 return lhs.m_value == rhs;
459 template <
typename T2>
460 bool operator!=(
const nullable<T2>& lhs,
const T2& rhs)
465 return lhs.m_value != rhs;
468 template <
typename T2>
469 bool operator==(
const T2& lhs,
const nullable<T2>& rhs)
474 return lhs == rhs.m_value;
477 template <
typename T2>
478 bool operator!=(
const T2& lhs,
const nullable<T2>& rhs)
483 return lhs != rhs.m_value;
486 template <
typename T2>
487 std::enable_if_t<!std::is_reference_v<T2>,
bool> operator==(
const nullable<T2>& lhs, std::nullptr_t)
489 return !lhs.m_hasValue;
492 template <
typename T2>
493 std::enable_if_t<!std::is_reference_v<T2>,
bool> operator!=(
const nullable<T2>& lhs, std::nullptr_t)
495 return lhs.m_hasValue;
498 template <
typename T2>
499 std::enable_if_t<!std::is_reference_v<T2>,
bool> operator==(std::nullptr_t,
const nullable<T2>& rhs)
501 return !rhs.m_hasValue;
504 template <
typename T2>
505 std::enable_if_t<!std::is_reference_v<T2>,
bool> operator!=(std::nullptr_t,
const nullable<T2>& rhs)
507 return rhs.m_hasValue;
510 template <
typename T2>
511 std::enable_if_t<std::is_reference_v<T2>,
bool> operator==(
const nullable<T2>& lhs, std::nullptr_t)
513 return lhs.m_value ==
nullptr;
516 template <
typename T2>
517 std::enable_if_t<std::is_reference_v<T2>,
bool> operator==(std::nullptr_t,
const nullable<T2>& rhs)
519 return rhs.m_value ==
nullptr;
522 template <
typename T2>
523 std::enable_if_t<std::is_reference_v<T2>,
bool> operator!=(
const nullable<T2>& lhs, std::nullptr_t)
525 return lhs.m_value !=
nullptr;
528 template <
typename T2>
529 std::enable_if_t<std::is_reference_v<T2>,
bool> operator!=(std::nullptr_t,
const nullable<T2>& rhs)
531 return rhs.m_value !=
nullptr;
534 template<
typename T2>
535 bool operator==(
const nullable<T2&>& lhs,
const T2* rhs)
537 return lhs.m_value == rhs;
540 template<
typename T2>
541 bool operator==(
const T2* lhs,
const nullable<T2&>& rhs)
543 return lhs == rhs.m_value;
546 template<
typename T2>
547 bool operator!=(
const nullable<T2&>& lhs,
const T2* rhs)
549 return lhs.m_value != rhs;
552 template<
typename T2>
553 bool operator!=(
const T2* lhs,
const nullable<T2&>& rhs)
555 return lhs != rhs.m_value;
Convenient type for char array storage and/or buffer with std::string compatibility.
Definition basetypes.h:38
Alternative to std::optional that supports reference (but not pointer) types.
Definition nullable.h:29
nullable & operator*=(T value)
This is same as operator=(T value), but allows to avoid ambiguities or picking wrong overload.
Definition nullable.h:104
SPDX-FileCopyrightText: (C) 2022 Francesco Pretto ceztko@gmail.com SPDX-License-Identifier: LGPL-2....
Definition basetypes.h:16