DtkCore
DTK Core module
dexpected.h
1// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: LGPL-3.0-or-later
4
5#ifndef DEXPECTED_H
6#define DEXPECTED_H
7
8#include <cassert>
9#include <cstdlib>
10#include <exception>
11#include <initializer_list>
12#include <memory>
13#include <type_traits>
14
15#include "derror.h"
16
17DCORE_BEGIN_NAMESPACE
18
19#define likely(x) __builtin_expect(static_cast<long int>((x)), 1)
20#define unlikely(x) __builtin_expect(reinterpret_cast<long int>((x)), 0)
21
22#if __cpp_exceptions
23#define _DEXPECTED_THROW_OR_ABORT(_EXC) (throw(_EXC))
24#else
25#define _DEXPECTED_THROW_OR_ABORT(_EXC) (std::abort())
26#endif
27
28template <typename T, typename E>
29class DExpected;
30
31template <typename E>
32class DUnexpected;
33
34template <bool v>
35using _bool_constant = std::integral_constant<bool, v>;
36
40enum class emplace_tag { USE_EMPLACE };
41
45enum class dunexpected_tag { DUNEXPECTED };
46
47template <typename Type>
49{
50 using type = typename std::remove_cv<typename std::remove_reference<Type>::type>::type;
51};
52
53template <typename E>
55
56template <>
57class bad_result_access<void> : public std::exception
58{
59protected:
60 bad_result_access() noexcept {}
61 bad_result_access(const bad_result_access &) = default;
63 bad_result_access &operator=(const bad_result_access &) = default;
64 bad_result_access &operator=(bad_result_access &&) = default;
65 ~bad_result_access() = default;
66
67public:
68 const char *what() const noexcept override { return "bad access to DExpected without value"; }
69};
70
71template <typename E>
73{
74public:
75 explicit bad_result_access(E _e)
76 : m_error(std::move(_e))
77 {
78 }
79
80 E &error() &noexcept { return m_error; }
81 const E &error() const &noexcept { return m_error; }
82
83 E error() &&noexcept { return std::move(m_error); }
84 const E error() const &&noexcept { return std::move(m_error); }
85
86private:
87 E m_error;
88};
89
90template <typename Type, typename... Args>
91auto construct_at(Type *p, Args &&...args) noexcept(noexcept(::new((void *)0) Type(std::declval<Args>()...)))
92 -> decltype(::new((void *)0) Type(std::declval<Args>()...))
93{
94 return ::new ((void *)p) Type(std::forward<Args>(args)...);
95}
96
97namespace __dexpected {
98template <typename ObjType>
99void destroy_at_obj(ObjType *p)
100{
101 p->~ObjType();
102}
103
104template <typename ArrType>
105void destroy_at_arr(ArrType *p)
106{
107 for (auto &elem : *p)
108 destroy_at_obj(std::addressof(elem));
109}
110} // namespace __dexpected
111
112template <typename Type, typename std::enable_if<std::is_array<Type>::value, bool>::type = true>
113void destroy_at(Type *p)
114{
115 __dexpected::destroy_at_arr(p);
116}
117
118template <typename Type, typename std::enable_if<!std::is_array<Type>::value, bool>::type = true>
119void destroy_at(Type *p)
120{
121 __dexpected::destroy_at_obj(p);
122}
123
124namespace __dexpected {
125template <typename T>
126struct Guard
127{
128 static_assert(std::is_nothrow_move_constructible<T>::value, "type T must bu nothrow_move_constructible");
129 explicit Guard(T &_x)
130 : m_guarded(std::addressof(_x))
131 , m_tmp(std::move(_x))
132 {
133 destroy_at(m_guarded);
134 }
135
136 ~Guard()
137 {
138 if (unlikely(m_guarded)) {
139 construct_at(m_guarded, std::move(m_tmp));
140 }
141 }
142 Guard(const Guard &) = delete;
143 Guard &operator=(const Guard &) = delete;
144
145 T &&release() noexcept { return std::move(m_tmp); }
146
147private:
148 T *m_guarded;
149 T m_tmp;
150};
151} // namespace __dexpected
152
153namespace __dexpected {
154
155template <typename T>
156struct _is_dexpected : public std::false_type
157{
158};
159
160template <typename T, typename E>
161struct _is_dexpected<DExpected<T, E>> : public std::true_type
162{
163};
164
165template <typename T>
166struct _is_dunexpected : public std::false_type
167{
168};
169
170template <typename T>
171struct _is_dunexpected<DUnexpected<T>> : public std::true_type
172{
173};
174
175template <typename E>
176constexpr bool _can_be_dunexpected()
177{
178 return std::is_object<E>::value and !std::is_array<E>::value and !_is_dunexpected<E>() and !std::is_const<E>::value and
179 !std::is_volatile<E>::value;
180}
181
182template <typename Tp,
183 typename Up,
184 typename Vp,
185 typename std::enable_if<std::is_nothrow_constructible<Tp, Vp>::value and std::is_nothrow_move_constructible<Tp>::value,
186 bool>::type = true>
187void reinit(Tp *_newVal, Up *_oldVal, Vp &&_arg) noexcept(std::is_nothrow_constructible<Tp, Vp>::value)
188{
189 destroy_at(_oldVal);
190 construct_at(_newVal, std::forward<Vp>(_arg));
191}
192
193template <typename Tp,
194 typename Up,
195 typename Vp,
196 typename std::enable_if<std::is_nothrow_constructible<Tp, Vp>::value and !std::is_nothrow_move_constructible<Tp>::value,
197 bool>::type = true>
198void reinit(Tp *_newVal, Up *_oldVal, Vp &&_arg) noexcept(std::is_nothrow_constructible<Tp, Vp>::value)
199{
200 destroy_at(_oldVal);
201 construct_at(_newVal, std::forward<Vp>(_arg));
202}
203
204template <typename Tp,
205 typename Up,
206 typename Vp,
207 typename std::enable_if<!std::is_nothrow_constructible<Tp, Vp>::value and std::is_nothrow_move_constructible<Tp>::value,
208 bool>::type = true>
209void reinit(Tp *_newVal, Up *_oldVal, Vp &&_arg) noexcept(std::is_nothrow_constructible<Tp, Vp>::value)
210{
211 Tp _tmp(std::forward<Vp>(_arg));
212 destroy_at(_oldVal);
213 construct_at(_newVal, std::move(_tmp));
214}
215
216template <
217 typename Tp,
218 typename Up,
219 typename Vp,
220 typename std::enable_if<!std::is_nothrow_constructible<Tp, Vp>::value and !std::is_nothrow_move_constructible<Tp>::value,
221 bool>::type = true>
222void reinit(Tp *_newVal, Up *_oldVal, Vp &&_arg) noexcept(std::is_nothrow_constructible<Tp, Vp>::value)
223{
224 __dexpected::Guard<Up> _guard(*_oldVal);
225 construct_at(_newVal, std::forward<Vp>(_arg));
226 _guard.release();
227}
228
229} // namespace __dexpected
230
237template <typename E = DError>
239{
240 static_assert(__dexpected::_can_be_dunexpected<E>(), "can't be dunexpected");
241
242public:
246 constexpr DUnexpected(const DUnexpected &) = default;
247
251 constexpr DUnexpected(DUnexpected &&) = default;
252
258 template <typename Er = E,
259 typename std::enable_if<!std::is_same<typename remove_cvref<Er>::type, DUnexpected>::value and
260 !std::is_same<typename remove_cvref<Er>::type, emplace_tag>::value and
261 std::is_constructible<E, Er>::value,
262 bool>::type = true>
263 constexpr explicit DUnexpected(Er &&_e) noexcept(std::is_nothrow_constructible<E, Er>::value)
264 : m_error(std::forward<Er>(_e))
265 {
266 }
267
276 template <typename... Args>
277 constexpr explicit DUnexpected(emplace_tag, Args &&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value)
278 : m_error(std::forward<Args>(args)...)
279 {
280 static_assert(std::is_constructible<E, Args...>::value, "can't construct E from args.");
281 }
282
293 template <typename U, typename... Args>
294 constexpr explicit DUnexpected(emplace_tag, std::initializer_list<U> _li, Args &&...args) noexcept(
295 std::is_nothrow_constructible<E, std::initializer_list<U> &, Args...>::value)
296 : m_error(_li, std::forward<Args>(args)...)
297 {
298 }
299
303 DUnexpected &operator=(const DUnexpected &) = default;
304
309
314 constexpr const E &error() const &noexcept { return m_error; }
315
320 E &error() &noexcept { return m_error; }
321
327 constexpr const E &&error() const &&noexcept { return std::move(m_error); }
328
334 E &&error() &&noexcept { return std::move(m_error); }
335
340 void swap(DUnexpected &_other)
341 {
342 using std::swap;
343 swap(m_error, _other.m_error);
344 }
345
352 template <typename Er>
353 friend constexpr bool operator==(const DUnexpected &_x, const DUnexpected<Er> _y)
354 {
355 return _x.m_error == _y.error();
356 }
357
361 friend void swap(DUnexpected &_x, DUnexpected &_y) { _x.swap(_y); }
362
363private:
364 E m_error;
365};
366
373template <typename T, typename E = DError>
375{
376 template <typename, typename>
377 friend class DExpected;
378 static_assert(!std::is_reference<T>::value, "type T can't be reference type");
379 static_assert(!std::is_function<T>::value, "type T can't be function type");
380 static_assert(!std::is_same<typename std::remove_cv<T>::type, dunexpected_tag>::value, "type T can't be dunexpected_tag");
381 static_assert(!std::is_same<typename std::remove_cv<T>::type, emplace_tag>::value, "type T can't be emplace_tag");
382 static_assert(!__dexpected::_is_dunexpected<typename std::remove_cv<T>::type>::value, "type T can't be DUnexpected");
383 static_assert(__dexpected::_can_be_dunexpected<E>(), "type E can't be dunexpected");
384
385 template <typename U, typename G, typename Unex = DUnexpected<E>>
386 static constexpr bool __cons_from_DExpected()
387 {
388 return std::is_constructible<T, DExpected<U, G> &>::value or std::is_constructible<T, DExpected<U, G>>::value or
389 std::is_constructible<T, const DExpected<U, G>>::value or
390 std::is_constructible<T, const DExpected<U, G> &>::value or std::is_convertible<DExpected<U, G> &, T>::value or
391 std::is_convertible<DExpected<U, G>, T>::value or std::is_convertible<const DExpected<U, G> &, T>::value or
392 std::is_convertible<const DExpected<U, G>, T>::value or std::is_constructible<Unex, DExpected<U, G> &>::value or
393 std::is_constructible<Unex, DExpected<U, G>>::value or
394 std::is_constructible<Unex, const DExpected<U, G> &>::value or
395 std::is_constructible<Unex, const DExpected<U, G>>::value;
396 }
397
398 template <typename U, typename G>
399 static constexpr bool __explicit_conv()
400 {
401 return !std::is_convertible<U, T>::value or !std::is_convertible<G, E>::value;
402 }
403
404 static constexpr bool des_value()
405 {
406 return !std::is_trivially_destructible<T>::value or !std::is_trivially_destructible<E>::value;
407 }
408
409 template <typename V>
410 void assign_val(V &&_v)
411 {
412 if (m_has_value) {
413 m_value = std::forward<V>(_v);
414 } else {
415 __dexpected::reinit(std::addressof(m_value), std::addressof(m_error), std::forward<V>(_v));
416 m_has_value = true;
417 }
418 }
419
420 template <typename V>
421 void assign_err(V &&_v)
422 {
423 if (m_has_value) {
424 __dexpected::reinit(std::addressof(m_error), std::addressof(m_value), std::forward<V>(_v));
425 m_has_value = false;
426 } else {
427 m_error = std::forward<V>(_v);
428 }
429 }
430
431 template <typename Ep = E, typename std::enable_if<std::is_nothrow_move_constructible<Ep>::value, bool>::type = true>
432 void swap_val_err(DExpected &_other) noexcept(
433 std::is_nothrow_move_constructible<Ep>::value and std::is_nothrow_move_constructible<T>::value)
434 {
435 __dexpected::Guard<E> _guard(_other.m_error);
436 construct_at(std::addressof(_other.m_value), std::move(m_value));
437 _other.m_has_value = true;
438 destroy_at(std::addressof(m_value));
439 construct_at(std::addressof(m_error), _guard.release());
440 m_has_value = false;
441 }
442
443 template <typename Ep = E, typename std::enable_if<!std::is_nothrow_move_constructible<Ep>::value, bool>::type = true>
444 void swap_val_err(DExpected &_other) noexcept(
445 std::is_nothrow_move_constructible<Ep>::value and std::is_nothrow_move_constructible<T>::value)
446 {
447 __dexpected::Guard<T> _guard(_other.m_value);
448 construct_at(std::addressof(m_error), std::move(_other.m_error));
449 m_has_value = false;
450 destroy_at(std::addressof(_other.m_error));
451 construct_at(std::addressof(_other.m_value), _guard.release());
452 _other.m_has_value = true;
453 }
454
455public:
456 using value_type = T;
457 using error_type = E;
459 template <typename U>
461
465 template <typename std::enable_if<std::is_default_constructible<T>::value, bool>::type = true>
466 constexpr DExpected() noexcept(std::is_nothrow_default_constructible<T>::value)
467 : m_has_value(true)
468 , m_value()
469 {
470 }
471
475 template <
476 typename std::enable_if<std::is_copy_constructible<T>::value and std::is_copy_constructible<E>::value, bool>::type = true>
477 DExpected(const DExpected &_x) noexcept(
478 std::is_nothrow_copy_constructible<T>::value and std::is_nothrow_copy_constructible<E>::value)
479 : m_has_value(_x.m_has_value)
480 {
481 if (m_has_value)
482 construct_at(std::addressof(m_value), _x.m_value);
483 else
484 construct_at(std::addressof(m_error), _x.m_error);
485 }
486
490 template <
491 typename std::enable_if<std::is_move_constructible<T>::value and std::is_move_constructible<E>::value, bool>::type = true>
492 DExpected(DExpected &&_x) noexcept(
493 std::is_nothrow_move_constructible<T>::value and std::is_nothrow_move_constructible<E>::value)
494 : m_has_value(_x.m_has_value)
495 {
496 if (m_has_value)
497 construct_at(std::addressof(m_value), std::move(_x).m_value);
498 else
499 construct_at(std::addressof(m_error), std::move(_x).m_error);
500 }
501
508 template <
509 typename U,
510 typename G,
511 typename std::enable_if<std::is_constructible<T, const U &>::value and std::is_constructible<E, const G &>::value and
512 !__cons_from_DExpected<U, G>() and !__explicit_conv<const U &, const G &>(),
513 bool>::type = true>
514 DExpected(const DExpected<U, G> &_x) noexcept(
515 std::is_nothrow_constructible<T, const U &>::value and std::is_nothrow_constructible<E, const G &>::value)
516 : m_has_value(_x.m_has_value)
517 {
518 if (m_has_value)
519 construct_at(std::addressof(m_value), _x.m_value);
520 else
521 construct_at(std::addressof(m_error), _x.m_error);
522 }
523
531 template <
532 typename U,
533 typename G,
534 typename std::enable_if<std::is_constructible<T, const U &>::value and std::is_constructible<E, const G &>::value and
535 !__cons_from_DExpected<U, G>() and __explicit_conv<const U &, const G &>(),
536 bool>::type = true>
537 explicit DExpected(const DExpected<U, G> &_x) noexcept(
538 std::is_nothrow_constructible<T, const U &>::value and std::is_nothrow_constructible<E, const G &>::value)
539 : m_has_value(_x.m_has_value)
540 {
541 if (m_has_value)
542 construct_at(std::addressof(m_value), _x.m_value);
543 else
544 construct_at(std::addressof(m_error), _x.m_error);
545 }
546
554 template <typename U,
555 typename G,
556 typename std::enable_if<std::is_constructible<T, U>::value and std::is_constructible<E, G>::value and
557 !__cons_from_DExpected<U, G>() and !__explicit_conv<U, G>(),
558 bool>::type = true>
559 DExpected(DExpected<U, G> &&_x) noexcept(
560 std::is_nothrow_constructible<T, U>::value and std::is_nothrow_constructible<E, G>::value)
561 : m_has_value(_x.m_has_value)
562 {
563 if (m_has_value)
564 construct_at(std::addressof(m_value), std::move(_x).m_value);
565 else
566 construct_at(std::addressof(m_error), std::move(_x).m_error);
567 }
568
576 template <typename U,
577 typename G,
578 typename std::enable_if<std::is_constructible<T, U>::value and std::is_constructible<E, G>::value and
579 !__cons_from_DExpected<U, G>() and __explicit_conv<U, G>(),
580 bool>::type = true>
581 explicit DExpected(DExpected<U, G> &&_x) noexcept(
582 std::is_nothrow_constructible<T, U>::value and std::is_nothrow_constructible<E, G>::value)
583 : m_has_value(_x.m_has_value)
584 {
585 if (m_has_value)
586 construct_at(std::addressof(m_value), std::move(_x).m_value);
587 else
588 construct_at(std::addressof(m_error), std::move(_x).m_error);
589 }
590
598 template <typename U = T,
599 typename std::enable_if<!std::is_same<typename remove_cvref<U>::type, DExpected>::value and
600 !std::is_same<typename remove_cvref<U>::type, emplace_tag>::value and
602 std::is_constructible<T, U>::value and !std::is_convertible<U, T>::value,
603 bool>::type = true>
604 constexpr explicit DExpected(U &&_v) noexcept(std::is_nothrow_constructible<T, U>::value)
605 : m_has_value(true)
606 , m_value(std::forward<U>(_v))
607
608 {
609 }
610
618 template <typename U = T,
619 typename std::enable_if<!std::is_same<typename remove_cvref<U>::type, DExpected>::value and
620 !std::is_same<typename remove_cvref<U>::type, emplace_tag>::value and
622 std::is_constructible<T, U>::value and std::is_convertible<U, T>::value,
623 bool>::type = true>
624 constexpr DExpected(U &&_v) noexcept(std::is_nothrow_constructible<T, U>::value)
625 : m_has_value(true)
626 , m_value(std::forward<U>(_v))
627 {
628 }
629
637 template <typename G = E,
638 typename std::enable_if<std::is_constructible<E, const G &>::value and !std::is_convertible<const G &, E>::value,
639 bool>::type = true>
640 constexpr explicit DExpected(const DUnexpected<G> &_u) noexcept(std::is_nothrow_constructible<E, const G &>::value)
641 : m_has_value(false)
642 , m_error(_u.error())
643 {
644 }
645
652 template <typename G = E,
653 typename std::enable_if<std::is_constructible<E, const G &>::value and std::is_convertible<const G &, E>::value,
654 bool>::type = true>
655 constexpr DExpected(const DUnexpected<G> &_u) noexcept(std::is_nothrow_constructible<E, const G &>::value)
656 : m_has_value(false)
657 , m_error(_u.error())
658 {
659 }
660
668 template <
669 typename G = E,
670 typename std::enable_if<std::is_constructible<E, G>::value and !std::is_convertible<G, E>::value, bool>::type = true>
671 constexpr explicit DExpected(DUnexpected<G> &&_u) noexcept(std::is_nothrow_constructible<E, G>::value)
672 : m_has_value(false)
673 , m_error(std::move(_u).error())
674 {
675 }
676
684 template <typename G = E,
685 typename std::enable_if<std::is_constructible<E, G>::value and std::is_convertible<G, E>::value, bool>::type = true>
686 constexpr DExpected(DUnexpected<G> &&_u) noexcept(std::is_nothrow_constructible<E, G>::value)
687 : m_has_value(false)
688 , m_error(std::move(_u).error())
689 {
690 }
691
699 template <typename... Args>
700 constexpr explicit DExpected(emplace_tag, Args &&...args) noexcept(std::is_nothrow_constructible<T, Args...>::value)
701 : m_has_value(true)
702 , m_value(std::forward<Args>(args)...)
703
704 {
705 static_assert(std::is_constructible<T, Args...>::value, "can't construct T from args.");
706 }
707
717 template <typename U, typename... Args>
718 constexpr explicit DExpected(emplace_tag, std::initializer_list<U> _li, Args &&...args) noexcept(
719 std::is_nothrow_constructible<T, std::initializer_list<U> &, Args...>::value)
720 : m_has_value(true)
721 , m_value(_li, std::forward<Args>(args)...)
722 {
723 static_assert(std::is_constructible<T, std::initializer_list<U> &, Args...>::value, "can't construct T from args.");
724 }
725
733 template <typename... Args>
734 constexpr explicit DExpected(dunexpected_tag, Args &&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value)
735 : m_has_value(false)
736 , m_error(std::forward<Args>(args)...)
737
738 {
739 static_assert(std::is_constructible<E, Args...>::value, "can't construct E from args.");
740 }
741
751 template <typename U, typename... Args>
752 constexpr explicit DExpected(dunexpected_tag, std::initializer_list<U> _li, Args &&...args) noexcept(
753 std::is_nothrow_constructible<E, std::initializer_list<U> &, Args...>::value)
754 : m_has_value(false)
755 , m_error(_li, std::forward<Args>(args)...)
756 {
757 static_assert(std::is_constructible<E, std::initializer_list<U> &, Args...>::value, "can't construct E from args.");
758 }
759
764 {
765 if (des_value()) {
766 if (m_has_value) {
767 destroy_at(std::addressof(m_value));
768 } else {
769 destroy_at(std::addressof(m_error));
770 }
771 }
772 }
773
777 DExpected &operator=(const DExpected &) = delete;
778
783 template <typename std::enable_if<std::is_copy_assignable<T>::value and std::is_copy_constructible<T>::value and
784 std::is_copy_assignable<E>::value and std::is_copy_constructible<E>::value and
785 (std::is_nothrow_move_constructible<T>::value or
786 std::is_nothrow_move_constructible<E>::value),
787 bool>::type = true>
788 DExpected &operator=(const DExpected &_x) noexcept(
789 std::is_nothrow_copy_constructible<T>::value and std::is_nothrow_copy_constructible<E>::value
790 and std::is_nothrow_copy_assignable<T>::value and std::is_nothrow_copy_assignable<E>::value)
791 {
792 if (_x.m_has_value)
793 this->assign_val(_x.m_value);
794 else
795 this->assign_err(_x.m_error);
796 return *this;
797 }
798
804 template <typename std::enable_if<std::is_move_assignable<T>::value and std::is_move_constructible<T>::value and
805 std::is_move_assignable<E>::value and std::is_move_constructible<E>::value and
806 (std::is_nothrow_move_constructible<T>::value or
807 std::is_nothrow_move_constructible<E>::value),
808 bool>::type = true>
810 std::is_nothrow_move_constructible<T>::value and std::is_nothrow_move_constructible<E>::value
811 and std::is_nothrow_move_assignable<T>::value and std::is_nothrow_move_assignable<E>::value)
812 {
813 if (_x.m_has_value)
814 assign_val(std::move(_x.m_value));
815 else
816 assign_err(std::move(_x.m_error));
817 return *this;
818 }
819
825 template <
826 typename U = T,
827 typename std::enable_if<!std::is_same<DExpected, typename remove_cvref<U>::type>::value and
829 std::is_constructible<T, U>::value and std::is_assignable<T &, U>::value and
830 (std::is_nothrow_constructible<T, U>::value or std::is_nothrow_move_constructible<T>::value or
831 std::is_nothrow_move_constructible<E>::value),
832 bool>::type = true>
834 {
835 assign_val(std::forward<U>(_v));
836 return *this;
837 }
838
844 template <typename G,
845 typename std::enable_if<std::is_constructible<E, const G &>::value and std::is_assignable<E &, const G &>::value and
846 (std::is_nothrow_constructible<E, const G &>::value or
847 std::is_nothrow_move_constructible<T>::value or std::is_move_constructible<E>::value),
848 bool>::type = true>
850 {
851 assign_err(_e.error());
852 return *this;
853 }
854
861 template <typename G,
862 typename std::enable_if<std::is_constructible<E, G>::value and std::is_assignable<E &, G>::value and
863 (std::is_nothrow_constructible<E, G>::value or
864 std::is_nothrow_move_constructible<T>::value or std::is_move_constructible<E>::value),
865 bool>::type = true>
867 {
868 assign_err(std::move(_e).error());
869 return *this;
870 }
871
878 template <typename... Args>
879 T &emplace(Args &&...args) noexcept
880 {
881 static_assert(std::is_nothrow_constructible<T, Args...>::value, "type T should have nothrow_constructible");
882 if (m_has_value)
883 destroy_at(std::addressof(m_value));
884 else {
885 destroy_at(std::addressof(m_error));
886 m_has_value = true;
887 }
888 construct_at(std::addressof(m_value), std::forward<Args>(args)...);
889 return m_value;
890 }
891
900 template <typename U, typename... Args>
901 T &emplace(std::initializer_list<U> li, Args &&...args) noexcept
902 {
903 static_assert(std::is_nothrow_constructible<T, std::initializer_list<U> &, Args...>::value,
904 "type T should have a noexcept constructor");
905 if (m_has_value)
906 destroy_at(std::addressof(m_value));
907 else {
908 destroy_at(std::addressof(m_error));
909 }
910 construct_at(std::addressof(m_value), li, std::forward<Args>(args)...);
911 return m_value;
912 }
913
914 // TODO:需要swap吗?
919 template <typename std::enable_if<std::is_move_constructible<T>::value and std::is_move_constructible<E>::value and
920 (std::is_nothrow_move_constructible<T>::value or
921 std::is_nothrow_move_constructible<E>::value),
922 bool>::type = true>
923 void
924 swap(DExpected &_x) noexcept(std::is_nothrow_move_constructible<T>::value and std::is_nothrow_move_constructible<E>::value)
925 {
926 if (m_has_value) {
927 if (_x.m_has_value) {
928 using std::swap;
929 swap(m_value, _x.m_value);
930 } else {
931 this->swap_val_err(_x);
932 }
933 } else {
934 if (_x.m_has_value)
935 _x.swap_val_err(*this);
936 else {
937 using std::swap;
938 swap(m_error, _x.m_error);
939 }
940 }
941 }
942
947 const T *operator->() const noexcept
948 {
949 assert(m_has_value);
950 return std::addressof(m_value);
951 }
952
957 T *operator->() noexcept
958 {
959 assert(m_has_value);
960 return std::addressof(m_value);
961 }
962
967 const T &operator*() const &noexcept
968 {
969 assert(m_has_value);
970 return m_value;
971 }
972
977 T &operator*() &noexcept
978 {
979 assert(m_has_value);
980 return m_value;
981 }
982
987 const T &&operator*() const &&noexcept
988 {
989 assert(m_has_value);
990 return std::move(m_value);
991 }
992
997 T &&operator*() &&noexcept
998 {
999 assert(m_has_value);
1000 return std::move(m_value);
1001 }
1002
1007 constexpr explicit operator bool() const noexcept { return m_has_value; }
1008
1013 constexpr bool hasValue() const noexcept { return m_has_value; }
1014
1019 const T &value() const &
1020 {
1021 if (likely(m_has_value)) {
1022 return m_value;
1023 }
1024 _DEXPECTED_THROW_OR_ABORT(bad_result_access<E>(m_error));
1025 }
1026
1031 T &value() &
1032 {
1033 if (likely(m_has_value)) {
1034 return m_value;
1035 }
1036 _DEXPECTED_THROW_OR_ABORT(bad_result_access<E>(m_error));
1037 }
1038
1044 const T &&value() const &&
1045 {
1046 if (likely(m_has_value)) {
1047 return std::move(m_value);
1048 }
1049 _DEXPECTED_THROW_OR_ABORT(bad_result_access<E>(m_error));
1050 }
1051
1057 T &&value() &&
1058 {
1059 if (likely(m_has_value)) {
1060 return std::move(m_value);
1061 }
1062 _DEXPECTED_THROW_OR_ABORT(bad_result_access<E>(m_error));
1063 }
1064
1069 const E &error() const &noexcept
1070 {
1071 assert(!m_has_value);
1072 return m_error;
1073 }
1074
1079 E &error() &noexcept
1080 {
1081 assert(!m_has_value);
1082 return m_error;
1083 }
1084
1090 const E &&error() const &&noexcept
1091 {
1092 assert(!m_has_value);
1093 return std::move(m_error);
1094 }
1095
1101 E &&error() &&noexcept
1102 {
1103 assert(!m_has_value);
1104 return std::move(m_error);
1105 }
1106
1107 // TODO:因为无法确定U转T时是否会抛出异常,所以都按抛出异常来
1114 template <typename U>
1115 T value_or(U &&_v) const &
1116 {
1117 static_assert(std::is_copy_constructible<T>::value, "type T should have an copy constructor.");
1118 static_assert(std::is_convertible<U, T>::value, "type U must can be converted to T.");
1119 if (m_has_value)
1120 return m_value;
1121 return static_cast<T>(std::forward<U>(_v));
1122 }
1123
1131 template <typename U>
1132 T value_or(U &&_v) &&
1133 {
1134 static_assert(std::is_move_constructible<T>::value, "type T must bu copy_constructible.");
1135 static_assert(std::is_convertible<U, T>::value, "type U must can be converted to T.");
1136 if (m_has_value)
1137 return std::move(m_value);
1138 return static_cast<T>(std::forward<U>(_v));
1139 }
1140
1144 template <typename U, typename E2, typename std::enable_if<!std::is_void<U>::value, bool>::type = true>
1145 friend bool
1147 const DExpected<U, E2> &_y) noexcept(noexcept(bool(*_x == *_y)) and noexcept(bool(_x.error() == _y.error())))
1148 {
1149 if (_x.hasValue())
1150 return _y.hasValue() and bool(*_x == *_y);
1151 else
1152 return !_y.hasValue() and bool(_x.error() == _x.error());
1153 }
1154
1158 template <typename U>
1159 friend constexpr bool operator==(const DExpected &_x, const U &_v) noexcept(noexcept(bool(*_x == _v)))
1160 {
1161 return _x.hasValue() && bool(*_x == _v);
1162 }
1163
1167 template <typename E2>
1168 friend constexpr bool operator==(const DExpected &_x,
1169 const DUnexpected<E2> &_e) noexcept(noexcept(bool(_x.error() == _e.error())))
1170 {
1171 return !_x.hasValue() && bool(_x.error() == _e.error());
1172 }
1173
1177 friend void swap(DExpected &_x, DExpected &_y) noexcept(noexcept(_x.swap(_y))) { _x.swap(_y); }
1178
1179private:
1180 bool m_has_value;
1181 union
1182 {
1183 T m_value;
1184 E m_error;
1185 };
1186};
1187
1192template <typename E>
1193class DExpected<void, E>
1194{
1195 static_assert(__dexpected::_can_be_dunexpected<E>(), "type E can't be DUnexpected.");
1196 static constexpr bool des_value() { return !std::is_trivially_destructible<E>::value; }
1197
1198 template <typename, typename>
1199 friend class DExpected;
1200
1201 template <typename U, typename G, typename Unex = DUnexpected<E>>
1202 static constexpr bool __cons_from_DExpected()
1203 {
1204 return std::is_constructible<Unex, DExpected<U, G> &>::value and std::is_constructible<Unex, DExpected<U, G>>::value and
1205 std::is_constructible<Unex, const DExpected<U, G> &>::value and
1206 std::is_constructible<Unex, const DExpected<U, G>>::value;
1207 }
1208
1209 template <typename V>
1210 void assign_err(V &&_v)
1211 {
1212 if (m_has_value) {
1213 construct_at(std::addressof(m_error), std::forward<V>(_v));
1214 m_has_value = false;
1215 } else {
1216 m_error = std::forward<V>(_v);
1217 }
1218 }
1219
1220public:
1221 using value_type = void;
1222 using error_type = E;
1224 template <typename U>
1226
1227 constexpr DExpected() noexcept
1228 : m_has_value(true)
1229 , m_void()
1230 {
1231 }
1232
1233 template <typename std::enable_if<std::is_copy_constructible<E>::value, bool>::type = true>
1234 DExpected(const DExpected &_x) noexcept(std::is_nothrow_copy_constructible<E>::value)
1235 : m_has_value(_x.m_has_value)
1236 , m_void()
1237 {
1238 if (!m_has_value)
1239 construct_at(std::addressof(m_error), _x.m_error);
1240 }
1241
1242 template <typename std::enable_if<std::is_move_constructible<E>::value, bool>::type = true>
1243 DExpected(DExpected &&_x) noexcept(std::is_nothrow_move_constructible<E>::value)
1244 : m_has_value(_x.m_has_value)
1245 , m_void()
1246 {
1247 if (!m_has_value)
1248 construct_at(std::addressof(m_error), std::move(_x).m_error);
1249 }
1250
1251 template <typename U,
1252 typename G,
1253 typename std::enable_if<std::is_void<U>::value and std::is_constructible<E, const G &>::value and
1254 !__cons_from_DExpected<U, G>() and !std::is_convertible<const G &, E>::value,
1255 bool>::type = true>
1256 explicit DExpected(const DExpected<U, G> &_x) noexcept(std::is_nothrow_constructible<E, const G &>::value)
1257 : m_has_value(_x.m_has_value)
1258 , m_void()
1259 {
1260 if (!m_has_value)
1261 construct_at(std::addressof(m_error), _x.m_error);
1262 }
1263
1264 template <typename U,
1265 typename G,
1266 typename std::enable_if<std::is_void<U>::value and std::is_constructible<E, const G &>::value and
1267 !__cons_from_DExpected<U, G>() and std::is_convertible<const G &, E>::value,
1268 bool>::type = true>
1269 DExpected(const DExpected<U, G> &_x) noexcept(std::is_nothrow_constructible<E, const G &>::value)
1270 : m_has_value(_x.m_has_value)
1271 , m_void()
1272 {
1273 if (!m_has_value)
1274 construct_at(std::addressof(m_error), _x.m_error);
1275 }
1276
1277 template <typename U,
1278 typename G,
1279 typename std::enable_if<std::is_void<U>::value and std::is_constructible<E, G>::value and
1280 __cons_from_DExpected<U, G>() and !std::is_convertible<G, E>::value,
1281 bool>::type = true>
1282 explicit DExpected(DExpected<U, G> &&_x) noexcept(std::is_nothrow_constructible<E, G>::value)
1283 : m_has_value(_x.m_has_value)
1284 , m_void()
1285 {
1286 if (!m_has_value)
1287 construct_at(std::addressof(m_error), std::move(_x).m_error);
1288 }
1289
1290 template <typename U,
1291 typename G,
1292 typename std::enable_if<std::is_void<U>::value and std::is_constructible<E, G>::value and
1293 __cons_from_DExpected<U, G>() and std::is_convertible<G, E>::value,
1294 bool>::type = true>
1295 DExpected(DExpected<U, G> &&_x) noexcept(std::is_nothrow_constructible<E, G>::value)
1296 : m_has_value(_x.m_has_value)
1297 , m_void()
1298 {
1299 if (!m_has_value)
1300 construct_at(std::addressof(m_error), std::move(_x).m_error);
1301 }
1302
1303 template <typename G = E,
1304 typename std::enable_if<std::is_constructible<E, const G &>::value and !std::is_convertible<const G &, E>::value,
1305 bool>::type = true>
1306 constexpr explicit DExpected(const DUnexpected<G> &_u) noexcept(std::is_nothrow_constructible<E, const G &>::value)
1307 : m_has_value(false)
1308 , m_error(_u.error())
1309 {
1310 }
1311
1312 template <typename G = E,
1313 typename std::enable_if<std::is_constructible<E, const G &>::value and std::is_convertible<const G &, E>::value,
1314 bool>::type = true>
1315 constexpr DExpected(const DUnexpected<G> &_u) noexcept(std::is_nothrow_constructible<E, const G &>::value)
1316 : m_has_value(false)
1317 , m_error(_u.error())
1318 {
1319 }
1320
1321 template <
1322 typename G = E,
1323 typename std::enable_if<std::is_constructible<E, G>::value and !std::is_convertible<G, E>::value, bool>::type = true>
1324 constexpr explicit DExpected(DUnexpected<G> &&_u) noexcept(std::is_nothrow_constructible<E, G>::value)
1325 : m_has_value(false)
1326 , m_error(std::move(_u).error())
1327 {
1328 }
1329
1330 template <typename G = E,
1331 typename std::enable_if<std::is_constructible<E, G>::value and std::is_convertible<G, E>::value, bool>::type = true>
1332 constexpr DExpected(DUnexpected<G> &&_u) noexcept(std::is_nothrow_constructible<E, G>::value)
1333 : m_has_value(false)
1334 , m_error(std::move(_u).error())
1335 {
1336 }
1337
1338 template <typename... Args>
1339 constexpr explicit DExpected(emplace_tag) noexcept
1340 : DExpected()
1341 {
1342 }
1343
1344 template <typename... Args>
1345 constexpr explicit DExpected(dunexpected_tag, Args &&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value)
1346 : m_has_value(false)
1347 , m_error(std::forward<Args>(args)...)
1348 {
1349 static_assert(std::is_constructible<E, Args...>::value, "type E can't construct from args");
1350 }
1351
1352 template <typename U, typename... Args>
1353 constexpr explicit DExpected(dunexpected_tag,
1354 std::initializer_list<U> _li,
1355 Args &&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value)
1356 : m_has_value(false)
1357 , m_error(_li, std::forward<Args>(args)...)
1358 {
1359 static_assert(std::is_constructible<E, std::initializer_list<U> &, Args...>::value, "type E can't construct from args");
1360 }
1361
1362 ~DExpected()
1363 {
1364 if (des_value() and !m_has_value) {
1365 destroy_at(std::addressof(m_error));
1366 }
1367 }
1368
1369 DExpected &operator=(const DExpected &) = delete;
1370
1371 template <
1372 typename std::enable_if<std::is_copy_constructible<E>::value and std::is_copy_assignable<E>::value, bool>::type = true>
1373 DExpected &operator=(const DExpected &_x) noexcept(
1374 std::is_nothrow_copy_constructible<E>::value and std::is_nothrow_copy_assignable<E>::value)
1375 {
1376 if (_x.m_has_value)
1377 emplace();
1378 else
1379 assign_err(_x.m_error);
1380 return *this;
1381 }
1382
1383 template <
1384 typename std::enable_if<std::is_move_constructible<E>::value and std::is_move_assignable<E>::value, bool>::type = true>
1385 DExpected &
1386 operator=(DExpected &&_x) noexcept(std::is_nothrow_move_constructible<E>::value and std::is_nothrow_move_assignable<E>::value)
1387 {
1388 if (_x.m_has_value)
1389 emplace();
1390 else
1391 assign_err(std::move(_x.m_error));
1392 return *this;
1393 }
1394
1395 template <typename G,
1396 typename std::enable_if<std::is_constructible<E, const G &>::value and std::is_assignable<E &, const G &>::value,
1397 bool>::type = true>
1398 DExpected &operator=(const DUnexpected<G> &_e)
1399 {
1400 assign_err(_e.error());
1401 return *this;
1402 }
1403
1404 template <
1405 typename G,
1406 typename std::enable_if<std::is_constructible<E, G>::value and std::is_assignable<E &, G>::value, bool>::type = true>
1407 DExpected &operator=(DUnexpected<G> &&_e)
1408 {
1409 assign_err(std::move(_e.error()));
1410 return *this;
1411 }
1412
1413 void emplace() noexcept
1414 {
1415 if (!m_has_value) {
1416 destroy_at(std::addressof(m_error));
1417 m_has_value = true;
1418 }
1419 }
1420
1421 template <typename std::enable_if<std::is_move_constructible<E>::value, bool>::type = true>
1422 void swap(DExpected &_x) noexcept(std::is_nothrow_move_constructible<E>::value)
1423 {
1424 if (m_has_value) {
1425 if (!_x.m_has_value) {
1426 construct_at(std::addressof(m_error), std::move(_x.m_error));
1427 destroy_at(std::addressof(_x.m_error));
1428 m_has_value = false;
1429 _x.m_has_value = true;
1430 }
1431 } else {
1432 if (_x.m_has_value) {
1433 construct_at(std::addressof(_x.m_error), std::move(m_error));
1434 destroy_at(std::addressof(m_error));
1435 m_has_value = true;
1436 _x.m_has_value = false;
1437 } else {
1438 using std::swap;
1439 swap(m_error, _x.m_error);
1440 }
1441 }
1442 }
1443
1444 constexpr explicit operator bool() const noexcept { return m_has_value; }
1445
1446 constexpr bool hasValue() const noexcept { return m_has_value; }
1447
1448 void operator*() const noexcept { assert(m_has_value); }
1449
1450 void value() const &
1451 {
1452 if (likely(m_has_value))
1453 return;
1454 _DEXPECTED_THROW_OR_ABORT(bad_result_access<E>(m_error));
1455 }
1456
1457 void value() &&
1458 {
1459 if (likely(m_has_value))
1460 return;
1461 _DEXPECTED_THROW_OR_ABORT(bad_result_access<E>(std::move(m_error)));
1462 }
1463
1464 const E &error() const &noexcept
1465 {
1466 assert(!m_has_value);
1467 return m_error;
1468 }
1469
1470 E &error() &noexcept
1471 {
1472 assert(!m_has_value);
1473 return m_error;
1474 }
1475
1476 const E &&error() const &&noexcept
1477 {
1478 assert(!m_has_value);
1479 return std::move(m_error);
1480 }
1481
1482 E &&error() &&noexcept
1483 {
1484 assert(!m_has_value);
1485 return std::move(m_error);
1486 }
1487
1488 template <typename U, typename E2, typename std::enable_if<std::is_void<U>::value, bool>::type = true>
1489 friend bool operator==(const DExpected &_x, const DExpected<U, E2> &_y) noexcept(noexcept(bool(_x.error() == _y.error())))
1490 {
1491 if (_x.hasValue())
1492 return _y.hasValue();
1493 else
1494 return !_y.hasValue() and bool(_x.error() == _y.error());
1495 }
1496
1497 template <typename E2>
1498 friend bool operator==(const DExpected &_x, const DUnexpected<E2> &_e) noexcept(noexcept(bool(_x.error() == _e.error())))
1499 {
1500 return !_x.hasValue() && bool(_x.error() == _e.error());
1501 }
1502
1503 // TODO:可能没有swap
1504 friend void swap(DExpected &_x, DExpected &_y) noexcept(noexcept(_x.swap(_y))) { _x.swap(_y); }
1505
1506private:
1507 bool m_has_value;
1508 union
1509 {
1510 struct
1511 {
1512 } m_void;
1513 E m_error;
1514 };
1515};
1516
1517DCORE_END_NAMESPACE
1518
1519#endif
模板类Dtk::Core::DExpected提供存储两个值之一的方式。Dtk::Core::DExpected的对象要么保有一个期待的T类型值,要么保有一个不期待的E类型值,不会没有值。
Definition: dexpected.h:375
constexpr DExpected(emplace_tag, Args &&...args) noexcept(std::is_nothrow_constructible< T, Args... >::value)
Dtk::Core::DExpected的转发构造函数,从参数直接构造出期待值
Definition: dexpected.h:700
T value_or(U &&_v) const &
如果有期待值返回期待值,否则返回传入的默认值
Definition: dexpected.h:1115
const T & operator*() const &noexcept
重载解引用运算符
Definition: dexpected.h:967
DExpected(const DExpected &_x) noexcept(std::is_nothrow_copy_constructible< T >::value and std::is_nothrow_copy_constructible< E >::value)
Dtk::Core::DExpected的拷贝构造函数
Definition: dexpected.h:477
constexpr DExpected(emplace_tag, std::initializer_list< U > _li, Args &&...args) noexcept(std::is_nothrow_constructible< T, std::initializer_list< U > &, Args... >::value)
Dtk::Core::DExpected的转发构造函数,从参数直接构造出期待值
Definition: dexpected.h:718
T * operator->() noexcept
重载箭头运算符
Definition: dexpected.h:957
constexpr DExpected(DUnexpected< G > &&_u) noexcept(std::is_nothrow_constructible< E, G >::value)
Dtk::Core::DExpected的移动构造函数,从Dtk::Core::DUnexpected构造出Dtk::Core::DExpected对象
Definition: dexpected.h:671
DExpected & operator=(DExpected &&_x) noexcept(std::is_nothrow_move_constructible< T >::value and std::is_nothrow_move_constructible< E >::value and std::is_nothrow_move_assignable< T >::value and std::is_nothrow_move_assignable< E >::value)
Dtk::Core::DExpected的移动赋值运算符
Definition: dexpected.h:809
friend constexpr bool operator==(const DExpected &_x, const U &_v) noexcept(noexcept(bool(*_x==_v)))
重载相等运算符
Definition: dexpected.h:1159
T value_or(U &&_v) &&
如果有期待值返回期待值,否则返回传入的默认值
Definition: dexpected.h:1132
T & emplace(std::initializer_list< U > li, Args &&...args) noexcept
从参数直接转发构造期待值
Definition: dexpected.h:901
DExpected(DExpected &&_x) noexcept(std::is_nothrow_move_constructible< T >::value and std::is_nothrow_move_constructible< E >::value)
Dtk::Core::DExpected的移动构造函数
Definition: dexpected.h:492
constexpr DExpected(dunexpected_tag, std::initializer_list< U > _li, Args &&...args) noexcept(std::is_nothrow_constructible< E, std::initializer_list< U > &, Args... >::value)
Dtk::Core::DExpected的转发构造函数,从参数直接构造出不期待值
Definition: dexpected.h:752
DExpected & operator=(const DUnexpected< G > &_e)
Dtk::Core::DExpected的拷贝赋值运算符
Definition: dexpected.h:849
const T * operator->() const noexcept
重载箭头运算符
Definition: dexpected.h:947
const E && error() const &&noexcept
获取Dtk::Core::DExpected的不期待值
Definition: dexpected.h:1090
T & value() &
获取Dtk::Core::DExpected的期待值
Definition: dexpected.h:1031
T && operator*() &&noexcept
重载解引用运算符
Definition: dexpected.h:997
T && value() &&
获取Dtk::Core::DExpected的期待值
Definition: dexpected.h:1057
constexpr DExpected() noexcept(std::is_nothrow_default_constructible< T >::value)
Dtk::Core::DExpected的默认构造函数
Definition: dexpected.h:466
E & error() &noexcept
获取Dtk::Core::DExpected的不期待值
Definition: dexpected.h:1079
DExpected & operator=(const DExpected &_x) noexcept(std::is_nothrow_copy_constructible< T >::value and std::is_nothrow_copy_constructible< E >::value and std::is_nothrow_copy_assignable< T >::value and std::is_nothrow_copy_assignable< E >::value)
Dtk::Core::DExpected的拷贝赋值运算符
Definition: dexpected.h:788
E && error() &&noexcept
获取Dtk::Core::DExpected的不期待值
Definition: dexpected.h:1101
const E & error() const &noexcept
获取Dtk::Core::DExpected的不期待值
Definition: dexpected.h:1069
constexpr DExpected(dunexpected_tag, Args &&...args) noexcept(std::is_nothrow_constructible< E, Args... >::value)
Dtk::Core::DExpected的转发构造函数,从参数直接构造出不期待值
Definition: dexpected.h:734
constexpr DExpected(U &&_v) noexcept(std::is_nothrow_constructible< T, U >::value)
Dtk::Core::DExpected的移动构造函数,直接从期待类型构造出Dtk::Core::DExpected对象
Definition: dexpected.h:604
~DExpected()
Dtk::Core::DExpected的析构函数
Definition: dexpected.h:763
friend bool operator==(const DExpected &_x, const DExpected< U, E2 > &_y) noexcept(noexcept(bool(*_x== *_y)) and noexcept(bool(_x.error()==_y.error())))
重载相等运算符
Definition: dexpected.h:1146
friend constexpr bool operator==(const DExpected &_x, const DUnexpected< E2 > &_e) noexcept(noexcept(bool(_x.error()==_e.error())))
重载相等运算符
Definition: dexpected.h:1168
const T & value() const &
获取Dtk::Core::DExpected的期待值
Definition: dexpected.h:1019
void swap(DExpected &_x) noexcept(std::is_nothrow_move_constructible< T >::value and std::is_nothrow_move_constructible< E >::value)
交换两个Dtk::Core::DExpected的值
Definition: dexpected.h:924
DExpected & operator=(const DExpected &)=delete
Dtk::Core::DExpected的默认拷贝赋值运算符
constexpr bool hasValue() const noexcept
判断Dtk::Core::DExpected是否有值
Definition: dexpected.h:1013
constexpr DExpected(const DUnexpected< G > &_u) noexcept(std::is_nothrow_constructible< E, const G & >::value)
Dtk::Core::DExpected的拷贝构造函数,从Dtk::Core::DUnexpected构造出Dtk::Core::DExpected对象
Definition: dexpected.h:640
T & emplace(Args &&...args) noexcept
从参数直接转发构造期待值
Definition: dexpected.h:879
const T && value() const &&
获取Dtk::Core::DExpected的期待值
Definition: dexpected.h:1044
DExpected & operator=(DUnexpected< G > &&_e)
Dtk::Core::DExpected的移动赋值运算符
Definition: dexpected.h:866
DExpected & operator=(U &&_v)
Dtk::Core::DExpected的转发赋值运算符
Definition: dexpected.h:833
const T && operator*() const &&noexcept
重载解引用运算符
Definition: dexpected.h:987
T & operator*() &noexcept
重载解引用运算符
Definition: dexpected.h:977
friend void swap(DExpected &_x, DExpected &_y) noexcept(noexcept(_x.swap(_y)))
交换两个Dtk::Core::DExpected中的值
Definition: dexpected.h:1177
类模板Dtk::Core::DUnexpected代表一个Dtk::Core::DExpected中存储的不期待的值
Definition: dexpected.h:239
constexpr DUnexpected(emplace_tag, Args &&...args) noexcept(std::is_nothrow_constructible< E, Args... >::value)
直接从参数构造出一个包含错误类型为E的对象的Dtk::Core::DUnexpected对象
Definition: dexpected.h:277
constexpr DUnexpected(DUnexpected &&)=default
Dtk::Core::DUnexpected的默认移动构造函数
DUnexpected & operator=(const DUnexpected &)=default
Dtk::Core::DUnexpected的默认拷贝赋值运算符
E && error() &&noexcept
获取Dtk::Core::DUnexpected持有的不期待值
Definition: dexpected.h:334
constexpr const E && error() const &&noexcept
获取Dtk::Core::DUnexpected持有的不期待值
Definition: dexpected.h:327
constexpr DUnexpected(Er &&_e) noexcept(std::is_nothrow_constructible< E, Er >::value)
使用类型E直接初始化一个Dtk::Core::DUnexpected对象
Definition: dexpected.h:263
constexpr const E & error() const &noexcept
获取Dtk::Core::DUnexpected持有的不期待值
Definition: dexpected.h:314
constexpr DUnexpected(emplace_tag, std::initializer_list< U > _li, Args &&...args) noexcept(std::is_nothrow_constructible< E, std::initializer_list< U > &, Args... >::value)
从参数和初始化列表构造出一个包含错误类型为E的对象的Dtk::Core::DUnexpected对象
Definition: dexpected.h:294
constexpr DUnexpected(const DUnexpected &)=default
Dtk::Core::DUnexpected的默认拷贝构造函数
void swap(DUnexpected &_other)
交换两个Dtk::Core::DUnexpected的值
Definition: dexpected.h:340
DUnexpected & operator=(DUnexpected &&)=default
Dtk::Core::DUnexpected的默认移动赋值运算符
E & error() &noexcept
获取Dtk::Core::DUnexpected持有的不期待值
Definition: dexpected.h:320
friend void swap(DUnexpected &_x, DUnexpected &_y)
交换两个Dtk::Core::DUnexpected的值
Definition: dexpected.h:361
friend constexpr bool operator==(const DUnexpected &_x, const DUnexpected< Er > _y)
重载相等运算符
Definition: dexpected.h:353
Definition: dexpected.h:73
Definition: dexpected.h:127
Definition: dexpected.h:157
Definition: dexpected.h:167
Definition: dexpected.h:49