General Utility Library for C++17 25.4.1
expected.h
Go to the documentation of this file.
1
25#ifndef GUL17_EXPECTED_H_
26#define GUL17_EXPECTED_H_
27
28#include <cassert>
29#include <exception>
30#include <functional>
31#include <type_traits>
32#include <utility>
33#include <variant>
34
35#include "gul17/traits.h"
36
37namespace gul17 {
38
54template <typename E>
56
92template <typename T, typename E>
94
100template <typename E>
102
104
105#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
106#define GUL17_EXPECTED_EXCEPTIONS_ENABLED
107#endif
108
109#if (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
110#ifndef GUL17_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
111#define GUL17_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
112namespace detail {
113template <class T>
115 : std::is_trivially_copy_constructible<T> {};
116#ifdef _GLIBCXX_VECTOR
117template <class T, class A>
118struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
119#endif
120} // namespace detail
121#endif
122
123#define GUL17_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
124 gul17::detail::is_trivially_copy_constructible<T>
125#define GUL17_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
126 std::is_trivially_copy_assignable<T>
127#define GUL17_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
128 std::is_trivially_destructible<T>
129#else
130#define GUL17_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
131 std::is_trivially_copy_constructible<T>
132#define GUL17_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
133 std::is_trivially_copy_assignable<T>
134#define GUL17_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
135 std::is_trivially_destructible<T>
136#endif
137
138template <class T, class E> class expected;
139
140template <class E>
141class unexpected
142{
143public:
144 static_assert(!std::is_same<E, void>::value, "E must not be void");
145
146 unexpected() = delete;
147 constexpr explicit unexpected(const E &e) : m_val(e) {}
148
149 constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {}
150
151 template <class... Args, typename std::enable_if<std::is_constructible<
152 E, Args &&...>::value>::type * = nullptr>
153 constexpr explicit unexpected(Args &&...args)
154 : m_val(std::forward<Args>(args)...) {}
155 template <
156 class U, class... Args,
157 typename std::enable_if<std::is_constructible<
158 E, std::initializer_list<U> &, Args &&...>::value>::type * = nullptr>
159 constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args)
160 : m_val(l, std::forward<Args>(args)...) {}
161
162 constexpr const E &value() const & { return m_val; }
163 constexpr E &value() & { return m_val; }
164 constexpr E &&value() && { return std::move(m_val); }
165 constexpr const E &&value() const && { return std::move(m_val); }
166
167private:
168 E m_val;
169};
170
171#ifdef __cpp_deduction_guides
172template <class E> unexpected(E) -> unexpected<E>;
173#endif
174
175template <class E>
176constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) {
177 return lhs.value() == rhs.value();
178}
179template <class E>
180constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
181 return lhs.value() != rhs.value();
182}
183template <class E>
184constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) {
185 return lhs.value() < rhs.value();
186}
187template <class E>
188constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
189 return lhs.value() <= rhs.value();
190}
191template <class E>
192constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
193 return lhs.value() > rhs.value();
194}
195template <class E>
196constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
197 return lhs.value() >= rhs.value();
198}
199
200template <class E>
202 return unexpected<typename std::decay<E>::type>(std::forward<E>(e));
203}
204
205struct unexpect_t {
206 unexpect_t() = default;
207};
208static constexpr unexpect_t unexpect{};
209
210namespace detail {
211template <typename E>
212[[noreturn]] constexpr void throw_exception(E &&e) {
213#ifdef GUL17_EXPECTED_EXCEPTIONS_ENABLED
214 throw std::forward<E>(e);
215#else
216 (void)e;
217#ifdef _MSC_VER
218 __assume(0);
219#else
221#endif
222#endif
223}
224
225// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
226namespace swap_adl_tests {
227// if swap ADL finds this then it would call std::swap otherwise (same signature)
228struct tag {};
229
230template <class T> tag swap(T &, T &);
231template <class T, std::size_t N> tag swap(T (&a)[N], T (&b)[N]);
232
233// helper functions to test if an unqualified swap is possible, and if it
234// becomes std::swap
235template <class, class> std::false_type can_swap(...) noexcept(false);
236template <class T, class U,
237 class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
238std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
239 std::declval<U &>())));
240
241template <class, class> std::false_type uses_std(...);
242template <class T, class U>
243std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
244uses_std(int);
245
246template <class T>
247struct is_std_swap_noexcept
248 : std::integral_constant<bool,
249 std::is_nothrow_move_constructible<T>::value &&
250 std::is_nothrow_move_assignable<T>::value> {};
251
252template <class T, std::size_t N>
253struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
254
255template <class T, class U>
256struct is_adl_swap_noexcept
257 : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
258} // namespace swap_adl_tests
259
260template <class T, class U = T>
261struct is_swappable
262 : std::integral_constant<
263 bool,
264 decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
265 (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
266 (std::is_move_assignable<T>::value &&
267 std::is_move_constructible<T>::value))> {};
268
269template <class T, std::size_t N>
270struct is_swappable<T[N], T[N]>
271 : std::integral_constant<
272 bool,
273 decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
274 (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(
275 0))::value ||
276 is_swappable<T, T>::value)> {};
277
278template <class T, class U = T>
280 : std::integral_constant<
281 bool,
282 is_swappable<T, U>::value &&
283 ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
284 detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
285 (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
286 detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {};
287
288// Trait for checking if a type is a gul17::expected
289template <class T> struct is_expected_impl : std::false_type {};
290template <class T, class E>
291struct is_expected_impl<expected<T, E>> : std::true_type {};
292template <class T> using is_expected = is_expected_impl<std::decay_t<T>>;
293
294template <class T, class E, class U>
295using expected_enable_forward_value = std::enable_if_t<
296 std::is_constructible<T, U &&>::value &&
297 !std::is_same<std::decay_t<U>, std::in_place_t>::value &&
298 !std::is_same<expected<T, E>, std::decay_t<U>>::value &&
299 !std::is_same<unexpected<E>, std::decay_t<U>>::value>;
300
301template <class T, class E, class U, class G, class UR, class GR>
302using expected_enable_from_other = std::enable_if_t<
303 std::is_constructible<T, UR>::value &&
304 std::is_constructible<E, GR>::value &&
305 !std::is_constructible<T, expected<U, G> &>::value &&
306 !std::is_constructible<T, expected<U, G> &&>::value &&
307 !std::is_constructible<T, const expected<U, G> &>::value &&
308 !std::is_constructible<T, const expected<U, G> &&>::value &&
309 !std::is_convertible<expected<U, G> &, T>::value &&
310 !std::is_convertible<expected<U, G> &&, T>::value &&
311 !std::is_convertible<const expected<U, G> &, T>::value &&
312 !std::is_convertible<const expected<U, G> &&, T>::value>;
313
314template <class T, class U>
315using is_void_or = std::conditional_t<std::is_void<T>::value, std::true_type, U>;
316
317template <class T>
320
321template <class T>
324
325template <class T>
327
328template <class T>
330
331struct no_init_t {};
332static constexpr no_init_t no_init{};
333
334// Implements the storage of the values, and ensures that the destructor is
335// trivial if it can be.
336//
337// This specialization is for where neither `T` or `E` is trivially
338// destructible, so the destructors must be called on destruction of the
339// `expected`
341 bool = std::is_trivially_destructible<E>::value>
343 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
344 constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
345
346 template <class... Args,
347 std::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
348 nullptr>
349 constexpr expected_storage_base(std::in_place_t, Args &&...args)
350 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
351
352 template <class U, class... Args,
353 std::enable_if_t<std::is_constructible<
354 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
355 constexpr expected_storage_base(std::in_place_t, std::initializer_list<U> il,
356 Args &&...args)
357 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
358 template <class... Args,
359 std::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
360 nullptr>
361 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
362 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
363
364 template <class U, class... Args,
365 std::enable_if_t<std::is_constructible<
366 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
367 constexpr explicit expected_storage_base(unexpect_t,
368 std::initializer_list<U> il,
369 Args &&...args)
370 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
371
372 ~expected_storage_base() {
373 if (m_has_val) {
374 m_val.~T();
375 } else {
376 m_unexpect.~unexpected<E>();
377 }
378 }
379 union {
380 T m_val;
381 unexpected<E> m_unexpect;
382 char m_no_init;
383 };
384 bool m_has_val;
385};
386
387// This specialization is for when both `T` and `E` are trivially-destructible,
388// so the destructor of the `expected` can be trivial.
389template <class T, class E> struct expected_storage_base<T, E, true, true> {
390 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
392
393 template <class... Args,
394 std::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
395 nullptr>
396 constexpr expected_storage_base(std::in_place_t, Args &&...args)
397 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
398
399 template <class U, class... Args,
400 std::enable_if_t<std::is_constructible<
401 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
402 constexpr expected_storage_base(std::in_place_t, std::initializer_list<U> il,
403 Args &&...args)
404 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
405 template <class... Args,
406 std::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
407 nullptr>
408 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
409 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
410
411 template <class U, class... Args,
412 std::enable_if_t<std::is_constructible<
413 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
414 constexpr explicit expected_storage_base(unexpect_t,
415 std::initializer_list<U> il,
416 Args &&...args)
417 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
418
419 ~expected_storage_base() = default;
420 union {
421 T m_val;
423 char m_no_init;
424 };
425 bool m_has_val;
426};
427
428// T is trivial, E is not.
429template <class T, class E> struct expected_storage_base<T, E, true, false> {
430 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
432 : m_no_init(), m_has_val(false) {}
433
434 template <class... Args,
435 std::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
436 nullptr>
437 constexpr expected_storage_base(std::in_place_t, Args &&...args)
438 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
439
440 template <class U, class... Args,
441 std::enable_if_t<std::is_constructible<
442 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
443 constexpr expected_storage_base(std::in_place_t, std::initializer_list<U> il,
444 Args &&...args)
445 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
446 template <class... Args,
447 std::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
448 nullptr>
449 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
450 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
451
452 template <class U, class... Args,
453 std::enable_if_t<std::is_constructible<
454 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
455 constexpr explicit expected_storage_base(unexpect_t,
456 std::initializer_list<U> il,
457 Args &&...args)
458 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
459
461 if (!m_has_val) {
462 m_unexpect.~unexpected<E>();
463 }
464 }
465
466 union {
467 T m_val;
469 char m_no_init;
470 };
471 bool m_has_val;
472};
473
474// E is trivial, T is not.
475template <class T, class E> struct expected_storage_base<T, E, false, true> {
476 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
478
479 template <class... Args,
480 std::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
481 nullptr>
482 constexpr expected_storage_base(std::in_place_t, Args &&...args)
483 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
484
485 template <class U, class... Args,
486 std::enable_if_t<std::is_constructible<
487 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
488 constexpr expected_storage_base(std::in_place_t, std::initializer_list<U> il,
489 Args &&...args)
490 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
491 template <class... Args,
492 std::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
493 nullptr>
494 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
495 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
496
497 template <class U, class... Args,
498 std::enable_if_t<std::is_constructible<
499 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
500 constexpr explicit expected_storage_base(unexpect_t,
501 std::initializer_list<U> il,
502 Args &&...args)
503 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
504
506 if (m_has_val) {
507 m_val.~T();
508 }
509 }
510 union {
511 T m_val;
513 char m_no_init;
514 };
515 bool m_has_val;
516};
517
518// `T` is `void`, `E` is trivially-destructible
519template <class E> struct expected_storage_base<void, E, false, true> {
520 #if __GNUC__ <= 5
521 //no constexpr for GCC 4/5 bug
522 #else
523 constexpr
524 #endif
526
528
529 constexpr expected_storage_base(std::in_place_t) : m_has_val(true) {}
530
531 template <class... Args,
532 std::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
533 nullptr>
534 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
535 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
536
537 template <class U, class... Args,
538 std::enable_if_t<std::is_constructible<
539 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
540 constexpr explicit expected_storage_base(unexpect_t,
541 std::initializer_list<U> il,
542 Args &&...args)
543 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
544
545 ~expected_storage_base() = default;
546 struct dummy {};
547 union {
549 dummy m_val;
550 };
551 bool m_has_val;
552};
553
554// `T` is `void`, `E` is not trivially-destructible
555template <class E> struct expected_storage_base<void, E, false, false> {
556 constexpr expected_storage_base() : m_dummy(), m_has_val(true) {}
558
559 constexpr expected_storage_base(std::in_place_t) : m_dummy(), m_has_val(true) {}
560
561 template <class... Args,
562 std::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
563 nullptr>
564 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
565 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
566
567 template <class U, class... Args,
568 std::enable_if_t<std::is_constructible<
569 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
570 constexpr explicit expected_storage_base(unexpect_t,
571 std::initializer_list<U> il,
572 Args &&...args)
573 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
574
576 if (!m_has_val) {
577 m_unexpect.~unexpected<E>();
578 }
579 }
580
581 union {
583 char m_dummy;
584 };
585 bool m_has_val;
586};
587
588// This base class provides some handy member functions which can be used in
589// further derived classes
590template <class T, class E>
593
594 template <class... Args> void construct(Args &&...args) noexcept {
595 new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
596 this->m_has_val = true;
597 }
598
599 template <class Rhs> void construct_with(Rhs &&rhs) noexcept {
600 new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
601 this->m_has_val = true;
602 }
603
604 template <class... Args> void construct_error(Args &&...args) noexcept {
605 new (std::addressof(this->m_unexpect))
606 unexpected<E>(std::forward<Args>(args)...);
607 this->m_has_val = false;
608 }
609
610#ifdef GUL17_EXPECTED_EXCEPTIONS_ENABLED
611
612 // These assign overloads ensure that the most efficient assignment
613 // implementation is used while maintaining the strong exception guarantee.
614 // The problematic case is where rhs has a value, but *this does not.
615 //
616 // This overload handles the case where we can just copy-construct `T`
617 // directly into place without throwing.
618 template <class U = T,
619 std::enable_if_t<std::is_nothrow_copy_constructible<U>::value>
620 * = nullptr>
621 void assign(const expected_operations_base &rhs) noexcept {
622 if (!this->m_has_val && rhs.m_has_val) {
623 geterr().~unexpected<E>();
624 construct(rhs.get());
625 } else {
627 }
628 }
629
630 // This overload handles the case where we can attempt to create a copy of
631 // `T`, then no-throw move it into place if the copy was successful.
632 template <class U = T,
633 std::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
634 std::is_nothrow_move_constructible<U>::value>
635 * = nullptr>
636 void assign(const expected_operations_base &rhs) noexcept {
637 if (!this->m_has_val && rhs.m_has_val) {
638 T tmp = rhs.get();
639 geterr().~unexpected<E>();
640 construct(std::move(tmp));
641 } else {
643 }
644 }
645
646 // This overload is the worst-case, where we have to move-construct the
647 // unexpected value into temporary storage, then try to copy the T into place.
648 // If the construction succeeds, then everything is fine, but if it throws,
649 // then we move the old unexpected value back into place before rethrowing the
650 // exception.
651 template <class U = T,
652 std::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
653 !std::is_nothrow_move_constructible<U>::value>
654 * = nullptr>
655 void assign(const expected_operations_base &rhs) {
656 if (!this->m_has_val && rhs.m_has_val) {
657 auto tmp = std::move(geterr());
658 geterr().~unexpected<E>();
659
660#ifdef GUL17_EXPECTED_EXCEPTIONS_ENABLED
661 try {
662 construct(rhs.get());
663 } catch (...) {
664 geterr() = std::move(tmp);
665 throw;
666 }
667#else
668 construct(rhs.get());
669#endif
670 } else {
672 }
673 }
674
675 // These overloads do the same as above, but for rvalues
676 template <class U = T,
677 std::enable_if_t<std::is_nothrow_move_constructible<U>::value>
678 * = nullptr>
679 void assign(expected_operations_base &&rhs) noexcept {
680 if (!this->m_has_val && rhs.m_has_val) {
681 geterr().~unexpected<E>();
682 construct(std::move(rhs).get());
683 } else {
684 assign_common(std::move(rhs));
685 }
686 }
687
688 template <class U = T,
689 std::enable_if_t<!std::is_nothrow_move_constructible<U>::value>
690 * = nullptr>
691 void assign(expected_operations_base &&rhs) {
692 if (!this->m_has_val && rhs.m_has_val) {
693 auto tmp = std::move(geterr());
694 geterr().~unexpected<E>();
695#ifdef GUL17_EXPECTED_EXCEPTIONS_ENABLED
696 try {
697 construct(std::move(rhs).get());
698 } catch (...) {
699 geterr() = std::move(tmp);
700 throw;
701 }
702#else
703 construct(std::move(rhs).get());
704#endif
705 } else {
706 assign_common(std::move(rhs));
707 }
708 }
709
710#else
711
712 // If exceptions are disabled then we can just copy-construct
713 void assign(const expected_operations_base &rhs) noexcept {
714 if (!this->m_has_val && rhs.m_has_val) {
715 geterr().~unexpected<E>();
716 construct(rhs.get());
717 } else {
719 }
720 }
721
722 void assign(expected_operations_base &&rhs) noexcept {
723 if (!this->m_has_val && rhs.m_has_val) {
724 geterr().~unexpected<E>();
725 construct(std::move(rhs).get());
726 } else {
727 assign_common(std::move(rhs));
728 }
729 }
730
731#endif
732
733 // The common part of move/copy assigning
734 template <class Rhs> void assign_common(Rhs &&rhs) {
735 if (this->m_has_val) {
736 if (rhs.m_has_val) {
737 get() = std::forward<Rhs>(rhs).get();
738 } else {
739 destroy_val();
740 construct_error(std::forward<Rhs>(rhs).geterr());
741 }
742 } else {
743 if (!rhs.m_has_val) {
744 geterr() = std::forward<Rhs>(rhs).geterr();
745 }
746 }
747 }
748
749 bool has_value() const { return this->m_has_val; }
750
751 constexpr T &get() & { return this->m_val; }
752 constexpr const T &get() const & { return this->m_val; }
753 constexpr T &&get() && { return std::move(this->m_val); }
754 constexpr const T &&get() const && { return std::move(this->m_val); }
755
756 constexpr unexpected<E> &geterr() & {
757 return this->m_unexpect;
758 }
759 constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
760 constexpr unexpected<E> &&geterr() && {
761 return std::move(this->m_unexpect);
762 }
763 constexpr const unexpected<E> &&geterr() const && {
764 return std::move(this->m_unexpect);
765 }
766
767 constexpr void destroy_val() { get().~T(); }
768};
769
770// This base class provides some handy member functions which can be used in
771// further derived classes
772template <class E>
774 using expected_storage_base<void, E>::expected_storage_base;
775
776 template <class... Args> void construct() noexcept { this->m_has_val = true; }
777
778 // This function doesn't use its argument, but needs it so that code in
779 // levels above this can work independently of whether T is void
780 template <class Rhs> void construct_with(Rhs &&) noexcept {
781 this->m_has_val = true;
782 }
783
784 template <class... Args> void construct_error(Args &&...args) noexcept {
785 new (std::addressof(this->m_unexpect))
786 unexpected<E>(std::forward<Args>(args)...);
787 this->m_has_val = false;
788 }
789
790 template <class Rhs> void assign(Rhs &&rhs) noexcept {
791 if (!this->m_has_val) {
792 if (rhs.m_has_val) {
793 geterr().~unexpected<E>();
794 construct();
795 } else {
796 geterr() = std::forward<Rhs>(rhs).geterr();
797 }
798 } else {
799 if (!rhs.m_has_val) {
800 construct_error(std::forward<Rhs>(rhs).geterr());
801 }
802 }
803 }
804
805 bool has_value() const { return this->m_has_val; }
806
807 constexpr unexpected<E> &geterr() & {
808 return this->m_unexpect;
809 }
810 constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
811 constexpr unexpected<E> &&geterr() && {
812 return std::move(this->m_unexpect);
813 }
814 constexpr const unexpected<E> &&geterr() const && {
815 return std::move(this->m_unexpect);
816 }
817
818 constexpr void destroy_val() {
819 // no-op
820 }
821};
822
823// This class manages conditionally having a trivial copy constructor
824// This specialization is for when T and E are trivially copy constructible
825template <class T, class E,
830};
831
832// This specialization is for when T or E are not trivially copy constructible
833template <class T, class E>
836
837 expected_copy_base() = default;
840 if (rhs.has_value()) {
841 this->construct_with(rhs);
842 } else {
843 this->construct_error(rhs.geterr());
844 }
845 }
846
848 expected_copy_base &operator=(const expected_copy_base &rhs) = default;
849 expected_copy_base &operator=(expected_copy_base &&rhs) = default;
850};
851
852// This class manages conditionally having a trivial move constructor
853template <class T, class E,
855 &&std::is_trivially_move_constructible<E>::value>
857 using expected_copy_base<T, E>::expected_copy_base;
858};
859
860template <class T, class E>
862 using expected_copy_base<T, E>::expected_copy_base;
863
864 expected_move_base() = default;
865 expected_move_base(const expected_move_base &rhs) = default;
866
867 expected_move_base(expected_move_base &&rhs) noexcept(
868 std::is_nothrow_move_constructible<T>::value)
869 : expected_copy_base<T, E>(no_init) {
870 if (rhs.has_value()) {
871 this->construct_with(std::move(rhs));
872 } else {
873 this->construct_error(std::move(rhs.geterr()));
874 }
875 }
876 expected_move_base &operator=(const expected_move_base &rhs) = default;
877 expected_move_base &operator=(expected_move_base &&rhs) = default;
878};
879
880// This class manages conditionally having a trivial copy assignment operator
881template <class T, class E,
882 bool = is_void_or<
891};
892
893template <class T, class E>
896
897 expected_copy_assign_base() = default;
899
902 this->assign(rhs);
903 return *this;
904 }
906 operator=(expected_copy_assign_base &&rhs) = default;
907};
908
909// This class manages conditionally having a trivial move assignment operator
910template <class T, class E,
911 bool =
913 std::is_trivially_move_constructible<T>,
914 std::is_trivially_move_assignable<T>>>::
915 value &&std::is_trivially_destructible<E>::value
916 &&std::is_trivially_move_constructible<E>::value
917 &&std::is_trivially_move_assignable<E>::value>
919 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
920};
921
922template <class T, class E>
925 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
926
927 expected_move_assign_base() = default;
928 expected_move_assign_base(const expected_move_assign_base &rhs) = default;
929
930 expected_move_assign_base(expected_move_assign_base &&rhs) = default;
931
932 expected_move_assign_base &
933 operator=(const expected_move_assign_base &rhs) = default;
934
935 expected_move_assign_base &
936 operator=(expected_move_assign_base &&rhs) noexcept(
937 std::is_nothrow_move_constructible<T>::value
938 &&std::is_nothrow_move_assignable<T>::value) {
939 this->assign(std::move(rhs));
940 return *this;
941 }
942};
943
944// expected_delete_ctor_base will conditionally delete copy and move
945// constructors depending on whether T is copy/move constructible
946template <class T, class E,
947 bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
948 std::is_copy_constructible<E>::value),
949 bool EnableMove = (is_move_constructible_or_void<T>::value &&
950 std::is_move_constructible<E>::value)>
952 expected_delete_ctor_base() = default;
953 expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
954 expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
955 expected_delete_ctor_base &
956 operator=(const expected_delete_ctor_base &) = default;
957 expected_delete_ctor_base &
958 operator=(expected_delete_ctor_base &&) noexcept = default;
959};
960
961template <class T, class E>
962struct expected_delete_ctor_base<T, E, true, false> {
963 expected_delete_ctor_base() = default;
964 expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
965 expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
966 expected_delete_ctor_base &
967 operator=(const expected_delete_ctor_base &) = default;
968 expected_delete_ctor_base &
969 operator=(expected_delete_ctor_base &&) noexcept = default;
970};
971
972template <class T, class E>
973struct expected_delete_ctor_base<T, E, false, true> {
974 expected_delete_ctor_base() = default;
975 expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
976 expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
977 expected_delete_ctor_base &
978 operator=(const expected_delete_ctor_base &) = default;
979 expected_delete_ctor_base &
980 operator=(expected_delete_ctor_base &&) noexcept = default;
981};
982
983template <class T, class E>
984struct expected_delete_ctor_base<T, E, false, false> {
985 expected_delete_ctor_base() = default;
986 expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
987 expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
988 expected_delete_ctor_base &
989 operator=(const expected_delete_ctor_base &) = default;
990 expected_delete_ctor_base &
991 operator=(expected_delete_ctor_base &&) noexcept = default;
992};
993
994// expected_delete_assign_base will conditionally delete copy and move
995// constructors depending on whether T and E are copy/move constructible +
996// assignable
997template <class T, class E,
998 bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
999 std::is_copy_constructible<E>::value &&
1000 is_copy_assignable_or_void<T>::value &&
1001 std::is_copy_assignable<E>::value),
1002 bool EnableMove = (is_move_constructible_or_void<T>::value &&
1003 std::is_move_constructible<E>::value &&
1004 is_move_assignable_or_void<T>::value &&
1005 std::is_move_assignable<E>::value)>
1006struct expected_delete_assign_base {
1007 expected_delete_assign_base() = default;
1008 expected_delete_assign_base(const expected_delete_assign_base &) = default;
1009 expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
1010 default;
1011 expected_delete_assign_base &
1012 operator=(const expected_delete_assign_base &) = default;
1013 expected_delete_assign_base &
1014 operator=(expected_delete_assign_base &&) noexcept = default;
1015};
1016
1017template <class T, class E>
1018struct expected_delete_assign_base<T, E, true, false> {
1019 expected_delete_assign_base() = default;
1020 expected_delete_assign_base(const expected_delete_assign_base &) = default;
1021 expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
1022 default;
1023 expected_delete_assign_base &
1024 operator=(const expected_delete_assign_base &) = default;
1025 expected_delete_assign_base &
1026 operator=(expected_delete_assign_base &&) noexcept = delete;
1027};
1028
1029template <class T, class E>
1030struct expected_delete_assign_base<T, E, false, true> {
1031 expected_delete_assign_base() = default;
1032 expected_delete_assign_base(const expected_delete_assign_base &) = default;
1033 expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
1034 default;
1035 expected_delete_assign_base &
1036 operator=(const expected_delete_assign_base &) = delete;
1037 expected_delete_assign_base &
1038 operator=(expected_delete_assign_base &&) noexcept = default;
1039};
1040
1041template <class T, class E>
1042struct expected_delete_assign_base<T, E, false, false> {
1043 expected_delete_assign_base() = default;
1044 expected_delete_assign_base(const expected_delete_assign_base &) = default;
1045 expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
1046 default;
1047 expected_delete_assign_base &
1048 operator=(const expected_delete_assign_base &) = delete;
1049 expected_delete_assign_base &
1050 operator=(expected_delete_assign_base &&) noexcept = delete;
1051};
1052
1053// This is needed to be able to construct the expected_default_ctor_base which
1054// follows, while still conditionally deleting the default constructor.
1055struct default_constructor_tag {
1056 explicit constexpr default_constructor_tag() = default;
1057};
1058
1059// expected_default_ctor_base will ensure that expected has a deleted default
1060// consturctor if T is not default constructible.
1061// This specialization is for when T is default constructible
1062template <class T, class E,
1063 bool Enable =
1064 std::is_default_constructible<T>::value || std::is_void<T>::value>
1065struct expected_default_ctor_base {
1066 constexpr expected_default_ctor_base() noexcept = default;
1067 constexpr expected_default_ctor_base(
1068 expected_default_ctor_base const &) noexcept = default;
1069 constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
1070 default;
1071 expected_default_ctor_base &
1072 operator=(expected_default_ctor_base const &) noexcept = default;
1073 expected_default_ctor_base &
1074 operator=(expected_default_ctor_base &&) noexcept = default;
1075
1076 constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
1077};
1078
1079// This specialization is for when T is not default constructible
1080template <class T, class E> struct expected_default_ctor_base<T, E, false> {
1081 constexpr expected_default_ctor_base() noexcept = delete;
1082 constexpr expected_default_ctor_base(
1083 expected_default_ctor_base const &) noexcept = default;
1084 constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
1085 default;
1086 expected_default_ctor_base &
1087 operator=(expected_default_ctor_base const &) noexcept = default;
1088 expected_default_ctor_base &
1089 operator=(expected_default_ctor_base &&) noexcept = default;
1090
1091 constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
1092};
1093} // namespace detail
1094
1095template <typename E>
1096class bad_expected_access;
1097
1098template <> class bad_expected_access<void> : public std::exception
1099{
1100public:
1101 virtual const char *what() const noexcept override {
1102 return "Bad expected access";
1103 }
1104
1105protected:
1106 bad_expected_access() noexcept {}
1107 bad_expected_access(const bad_expected_access&) = default;
1108 bad_expected_access(bad_expected_access&&) = default;
1109 bad_expected_access& operator=(const bad_expected_access&) = default;
1110 bad_expected_access& operator=(bad_expected_access&&) = default;
1111 ~bad_expected_access() = default;
1112};
1113
1114template <class E>
1115class bad_expected_access : public bad_expected_access<void>
1116{
1117public:
1118 explicit bad_expected_access(E e) : m_val(std::move(e)) {}
1119
1120 const E &error() const & { return m_val; }
1121 E &error() & { return m_val; }
1122 const E &&error() const && { return std::move(m_val); }
1123 E &&error() && { return std::move(m_val); }
1124
1125private:
1126 E m_val;
1127};
1128
1129template <class T, class E>
1130class expected : private detail::expected_move_assign_base<T, E>,
1131 private detail::expected_delete_ctor_base<T, E>,
1132 private detail::expected_delete_assign_base<T, E>,
1133 private detail::expected_default_ctor_base<T, E> {
1134 static_assert(!std::is_reference<T>::value, "T must not be a reference");
1135 static_assert(!std::is_same<T, std::remove_cv<std::in_place_t>::type>::value,
1136 "T must not be std::in_place_t");
1137 static_assert(!std::is_same<T, std::remove_cv<unexpect_t>::type>::value,
1138 "T must not be unexpect_t");
1139 static_assert(
1140 !std::is_same<T, typename std::remove_cv<unexpected<E>>::type>::value,
1141 "T must not be unexpected<E>");
1142 static_assert(!std::is_reference<E>::value, "E must not be a reference");
1143
1144 T *valptr() { return std::addressof(this->m_val); }
1145 const T *valptr() const { return std::addressof(this->m_val); }
1146 unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
1147 const unexpected<E> *errptr() const {
1148 return std::addressof(this->m_unexpect);
1149 }
1150
1151 template <class U = T,
1152 std::enable_if_t<!std::is_void<U>::value> * = nullptr>
1153 constexpr U &val() {
1154 return this->m_val;
1155 }
1156 constexpr unexpected<E> &err() { return this->m_unexpect; }
1157
1158 template <class U = T,
1159 std::enable_if_t<!std::is_void<U>::value> * = nullptr>
1160 constexpr const U &val() const {
1161 return this->m_val;
1162 }
1163 constexpr const unexpected<E> &err() const { return this->m_unexpect; }
1164
1165 using impl_base = detail::expected_move_assign_base<T, E>;
1166 using ctor_base = detail::expected_default_ctor_base<T, E>;
1167
1168public:
1169 typedef T value_type;
1170 typedef E error_type;
1171 typedef unexpected<E> unexpected_type;
1172
1173 template <class F> constexpr auto and_then(F &&f) & {
1174 return and_then_impl(*this, std::forward<F>(f));
1175 }
1176 template <class F> constexpr auto and_then(F &&f) && {
1177 return and_then_impl(std::move(*this), std::forward<F>(f));
1178 }
1179 template <class F> constexpr auto and_then(F &&f) const & {
1180 return and_then_impl(*this, std::forward<F>(f));
1181 }
1182 template <class F> constexpr auto and_then(F &&f) const && {
1183 return and_then_impl(std::move(*this), std::forward<F>(f));
1184 }
1185
1186 template <class F> constexpr auto map(F &&f) & {
1187 return expected_map_impl(*this, std::forward<F>(f));
1188 }
1189 template <class F> constexpr auto map(F &&f) && {
1190 return expected_map_impl(std::move(*this), std::forward<F>(f));
1191 }
1192 template <class F> constexpr auto map(F &&f) const & {
1193 return expected_map_impl(*this, std::forward<F>(f));
1194 }
1195 template <class F> constexpr auto map(F &&f) const && {
1196 return expected_map_impl(std::move(*this), std::forward<F>(f));
1197 }
1198
1199 template <class F> constexpr auto transform(F &&f) & {
1200 return expected_map_impl(*this, std::forward<F>(f));
1201 }
1202 template <class F> constexpr auto transform(F &&f) && {
1203 return expected_map_impl(std::move(*this), std::forward<F>(f));
1204 }
1205 template <class F> constexpr auto transform(F &&f) const & {
1206 return expected_map_impl(*this, std::forward<F>(f));
1207 }
1208 template <class F> constexpr auto transform(F &&f) const && {
1209 return expected_map_impl(std::move(*this), std::forward<F>(f));
1210 }
1211
1212 template <class F> constexpr auto map_error(F &&f) & {
1213 return map_error_impl(*this, std::forward<F>(f));
1214 }
1215 template <class F> constexpr auto map_error(F &&f) && {
1216 return map_error_impl(std::move(*this), std::forward<F>(f));
1217 }
1218 template <class F> constexpr auto map_error(F &&f) const & {
1219 return map_error_impl(*this, std::forward<F>(f));
1220 }
1221 template <class F> constexpr auto map_error(F &&f) const && {
1222 return map_error_impl(std::move(*this), std::forward<F>(f));
1223 }
1224
1225 template <class F> constexpr auto transform_error(F &&f) & {
1226 return map_error_impl(*this, std::forward<F>(f));
1227 }
1228 template <class F> constexpr auto transform_error(F &&f) && {
1229 return map_error_impl(std::move(*this), std::forward<F>(f));
1230 }
1231 template <class F> constexpr auto transform_error(F &&f) const & {
1232 return map_error_impl(*this, std::forward<F>(f));
1233 }
1234 template <class F> constexpr auto transform_error(F &&f) const && {
1235 return map_error_impl(std::move(*this), std::forward<F>(f));
1236 }
1237
1238 template <class F> expected constexpr or_else(F &&f) & {
1239 return or_else_impl(*this, std::forward<F>(f));
1240 }
1241
1242 template <class F> expected constexpr or_else(F &&f) && {
1243 return or_else_impl(std::move(*this), std::forward<F>(f));
1244 }
1245
1246 template <class F> expected constexpr or_else(F &&f) const & {
1247 return or_else_impl(*this, std::forward<F>(f));
1248 }
1249
1250 template <class F> expected constexpr or_else(F &&f) const && {
1251 return or_else_impl(std::move(*this), std::forward<F>(f));
1252 }
1253
1254 constexpr expected() = default;
1255 constexpr expected(const expected &rhs) = default;
1256 constexpr expected(expected &&rhs) = default;
1257 expected &operator=(const expected &rhs) = default;
1258 expected &operator=(expected &&rhs) = default;
1259
1260 template <class... Args,
1261 std::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
1262 nullptr>
1263 constexpr expected(std::in_place_t, Args &&...args)
1264 : impl_base(std::in_place, std::forward<Args>(args)...),
1265 ctor_base(detail::default_constructor_tag{}) {}
1266
1267 template <class U, class... Args,
1268 std::enable_if_t<std::is_constructible<
1269 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1270 constexpr expected(std::in_place_t, std::initializer_list<U> il, Args &&...args)
1271 : impl_base(std::in_place, il, std::forward<Args>(args)...),
1272 ctor_base(detail::default_constructor_tag{}) {}
1273
1274 template <class G = E,
1275 std::enable_if_t<std::is_constructible<E, const G &>::value> * =
1276 nullptr,
1277 std::enable_if_t<!std::is_convertible<const G &, E>::value> * =
1278 nullptr>
1279 explicit constexpr expected(const unexpected<G> &e)
1280 : impl_base(unexpect, e.value()),
1281 ctor_base(detail::default_constructor_tag{}) {}
1282
1283 template <
1284 class G = E,
1285 std::enable_if_t<std::is_constructible<E, const G &>::value> * =
1286 nullptr,
1287 std::enable_if_t<std::is_convertible<const G &, E>::value> * = nullptr>
1288 constexpr expected(unexpected<G> const &e)
1289 : impl_base(unexpect, e.value()),
1290 ctor_base(detail::default_constructor_tag{}) {}
1291
1292 template <
1293 class G = E,
1294 std::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
1295 std::enable_if_t<!std::is_convertible<G &&, E>::value> * = nullptr>
1296 explicit constexpr expected(unexpected<G> &&e) noexcept(
1297 std::is_nothrow_constructible<E, G &&>::value)
1298 : impl_base(unexpect, std::move(e.value())),
1299 ctor_base(detail::default_constructor_tag{}) {}
1300
1301 template <
1302 class G = E,
1303 std::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
1304 std::enable_if_t<std::is_convertible<G &&, E>::value> * = nullptr>
1305 constexpr expected(unexpected<G> &&e) noexcept(
1306 std::is_nothrow_constructible<E, G &&>::value)
1307 : impl_base(unexpect, std::move(e.value())),
1308 ctor_base(detail::default_constructor_tag{}) {}
1309
1310 template <class... Args,
1311 std::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
1312 nullptr>
1313 constexpr explicit expected(unexpect_t, Args &&...args)
1314 : impl_base(unexpect, std::forward<Args>(args)...),
1315 ctor_base(detail::default_constructor_tag{}) {}
1316
1317 template <class U, class... Args,
1318 std::enable_if_t<std::is_constructible<
1319 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1320 constexpr explicit expected(unexpect_t, std::initializer_list<U> il,
1321 Args &&...args)
1322 : impl_base(unexpect, il, std::forward<Args>(args)...),
1323 ctor_base(detail::default_constructor_tag{}) {}
1324
1325 template <class U, class G,
1326 std::enable_if_t<!(std::is_convertible<U const &, T>::value &&
1327 std::is_convertible<G const &, E>::value)> * =
1328 nullptr,
1329 detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
1330 * = nullptr>
1331 explicit constexpr expected(const expected<U, G> &rhs)
1332 : ctor_base(detail::default_constructor_tag{}) {
1333 if (rhs.has_value()) {
1334 this->construct(*rhs);
1335 } else {
1336 this->construct_error(rhs.error());
1337 }
1338 }
1339
1340 template <class U, class G,
1341 std::enable_if_t<(std::is_convertible<U const &, T>::value &&
1342 std::is_convertible<G const &, E>::value)> * =
1343 nullptr,
1344 detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
1345 * = nullptr>
1346 constexpr expected(const expected<U, G> &rhs)
1347 : ctor_base(detail::default_constructor_tag{}) {
1348 if (rhs.has_value()) {
1349 this->construct(*rhs);
1350 } else {
1351 this->construct_error(rhs.error());
1352 }
1353 }
1354
1355 template <
1356 class U, class G,
1357 std::enable_if_t<!(std::is_convertible<U &&, T>::value &&
1358 std::is_convertible<G &&, E>::value)> * = nullptr,
1359 detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
1360 explicit constexpr expected(expected<U, G> &&rhs)
1361 : ctor_base(detail::default_constructor_tag{}) {
1362 if (rhs.has_value()) {
1363 this->construct(std::move(*rhs));
1364 } else {
1365 this->construct_error(std::move(rhs.error()));
1366 }
1367 }
1368
1369 template <
1370 class U, class G,
1371 std::enable_if_t<(std::is_convertible<U &&, T>::value &&
1372 std::is_convertible<G &&, E>::value)> * = nullptr,
1373 detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
1374 constexpr expected(expected<U, G> &&rhs)
1375 : ctor_base(detail::default_constructor_tag{}) {
1376 if (rhs.has_value()) {
1377 this->construct(std::move(*rhs));
1378 } else {
1379 this->construct_error(std::move(rhs.error()));
1380 }
1381 }
1382
1383 template <
1384 class U = T,
1385 std::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,
1386 detail::expected_enable_forward_value<T, E, U> * = nullptr>
1387 explicit constexpr expected(U &&v)
1388 : expected(std::in_place, std::forward<U>(v)) {}
1389
1390 template <
1391 class U = T,
1392 std::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr,
1393 detail::expected_enable_forward_value<T, E, U> * = nullptr>
1394 constexpr expected(U &&v)
1395 : expected(std::in_place, std::forward<U>(v)) {}
1396
1397 template <
1398 class U = T, class G = T,
1399 std::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * =
1400 nullptr,
1401 std::enable_if_t<!std::is_void<G>::value> * = nullptr,
1402 std::enable_if_t<
1403 (!std::is_same<expected<T, E>, std::decay_t<U>>::value &&
1404 !std::conjunction<std::is_scalar<T>,
1405 std::is_same<T, std::decay_t<U>>>::value &&
1406 std::is_constructible<T, U>::value &&
1407 std::is_assignable<G &, U>::value &&
1408 std::is_nothrow_move_constructible<E>::value)> * = nullptr>
1409 expected &operator=(U &&v) {
1410 if (has_value()) {
1411 val() = std::forward<U>(v);
1412 } else {
1413 err().~unexpected<E>();
1414 ::new (valptr()) T(std::forward<U>(v));
1415 this->m_has_val = true;
1416 }
1417
1418 return *this;
1419 }
1420
1421 template <
1422 class U = T, class G = T,
1423 std::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =
1424 nullptr,
1425 std::enable_if_t<!std::is_void<U>::value> * = nullptr,
1426 std::enable_if_t<
1427 (!std::is_same<expected<T, E>, std::decay_t<U>>::value &&
1428 !std::conjunction<std::is_scalar<T>,
1429 std::is_same<T, std::decay_t<U>>>::value &&
1430 std::is_constructible<T, U>::value &&
1431 std::is_assignable<G &, U>::value &&
1432 std::is_nothrow_move_constructible<E>::value)> * = nullptr>
1433 expected &operator=(U &&v) {
1434 if (has_value()) {
1435 val() = std::forward<U>(v);
1436 } else {
1437 auto tmp = std::move(err());
1438 err().~unexpected<E>();
1439
1440#ifdef GUL17_EXPECTED_EXCEPTIONS_ENABLED
1441 try {
1442 ::new (valptr()) T(std::forward<U>(v));
1443 this->m_has_val = true;
1444 } catch (...) {
1445 err() = std::move(tmp);
1446 throw;
1447 }
1448#else
1449 ::new (valptr()) T(std::forward<U>(v));
1450 this->m_has_val = true;
1451#endif
1452 }
1453
1454 return *this;
1455 }
1456
1457 template <class G = E,
1458 std::enable_if_t<std::is_nothrow_copy_constructible<G>::value &&
1459 std::is_assignable<G &, G>::value> * = nullptr>
1460 expected &operator=(const unexpected<G> &rhs) {
1461 if (!has_value()) {
1462 err() = rhs;
1463 } else {
1464 this->destroy_val();
1465 ::new (errptr()) unexpected<E>(rhs);
1466 this->m_has_val = false;
1467 }
1468
1469 return *this;
1470 }
1471
1472 template <class G = E,
1474 std::is_move_assignable<G>::value> * = nullptr>
1475 expected &operator=(unexpected<G> &&rhs) noexcept {
1476 if (!has_value()) {
1477 err() = std::move(rhs);
1478 } else {
1479 this->destroy_val();
1480 ::new (errptr()) unexpected<E>(std::move(rhs));
1481 this->m_has_val = false;
1482 }
1483
1484 return *this;
1485 }
1486
1488 T, Args &&...>::value> * = nullptr>
1489 void emplace(Args &&...args) {
1490 if (has_value()) {
1491 val().~T();
1492 } else {
1493 err().~unexpected<E>();
1494 this->m_has_val = true;
1495 }
1496 ::new (valptr()) T(std::forward<Args>(args)...);
1497 }
1498
1500 T, Args &&...>::value> * = nullptr>
1501 void emplace(Args &&...args) {
1502 if (has_value()) {
1503 val().~T();
1504 ::new (valptr()) T(std::forward<Args>(args)...);
1505 } else {
1506 auto tmp = std::move(err());
1507 err().~unexpected<E>();
1508
1509#ifdef GUL17_EXPECTED_EXCEPTIONS_ENABLED
1510 try {
1511 ::new (valptr()) T(std::forward<Args>(args)...);
1512 this->m_has_val = true;
1513 } catch (...) {
1514 err() = std::move(tmp);
1515 throw;
1516 }
1517#else
1518 ::new (valptr()) T(std::forward<Args>(args)...);
1519 this->m_has_val = true;
1520#endif
1521 }
1522 }
1523
1524 template <class U, class... Args,
1525 std::enable_if_t<std::is_nothrow_constructible<
1526 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1527 void emplace(std::initializer_list<U> il, Args &&...args) {
1528 if (has_value()) {
1529 T t(il, std::forward<Args>(args)...);
1530 val() = std::move(t);
1531 } else {
1532 err().~unexpected<E>();
1533 ::new (valptr()) T(il, std::forward<Args>(args)...);
1534 this->m_has_val = true;
1535 }
1536 }
1537
1538 template <class U, class... Args,
1540 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1541 void emplace(std::initializer_list<U> il, Args &&...args) {
1542 if (has_value()) {
1543 T t(il, std::forward<Args>(args)...);
1544 val() = std::move(t);
1545 } else {
1546 auto tmp = std::move(err());
1547 err().~unexpected<E>();
1548
1549#ifdef GUL17_EXPECTED_EXCEPTIONS_ENABLED
1550 try {
1551 ::new (valptr()) T(il, std::forward<Args>(args)...);
1552 this->m_has_val = true;
1553 } catch (...) {
1554 err() = std::move(tmp);
1555 throw;
1556 }
1557#else
1558 ::new (valptr()) T(il, std::forward<Args>(args)...);
1559 this->m_has_val = true;
1560#endif
1561 }
1562 }
1563
1564private:
1565 using t_is_void = std::true_type;
1566 using t_is_not_void = std::false_type;
1567 using t_is_nothrow_move_constructible = std::true_type;
1568 using move_constructing_t_can_throw = std::false_type;
1569 using e_is_nothrow_move_constructible = std::true_type;
1570 using move_constructing_e_can_throw = std::false_type;
1571
1572 void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept {
1573 // swapping void is a no-op
1574 }
1575
1577 using std::swap;
1578 swap(val(), rhs.val());
1579 }
1580
1581 void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept(
1582 std::is_nothrow_move_constructible<E>::value) {
1583 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1584 rhs.err().~unexpected_type();
1586 }
1587
1590 rhs, typename std::is_nothrow_move_constructible<T>::type{},
1591 typename std::is_nothrow_move_constructible<E>::type{});
1592 }
1593
1597 auto temp = std::move(val());
1598 val().~T();
1599 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1600 rhs.err().~unexpected_type();
1601 ::new (rhs.valptr()) T(std::move(temp));
1603 }
1604
1608 auto temp = std::move(val());
1609 val().~T();
1610#ifdef GUL17_EXPECTED_EXCEPTIONS_ENABLED
1611 try {
1612 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1613 rhs.err().~unexpected_type();
1614 ::new (rhs.valptr()) T(std::move(temp));
1616 } catch (...) {
1617 val() = std::move(temp);
1618 throw;
1619 }
1620#else
1621 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1622 rhs.err().~unexpected_type();
1623 ::new (rhs.valptr()) T(std::move(temp));
1625#endif
1626 }
1627
1631 auto temp = std::move(rhs.err());
1632 rhs.err().~unexpected_type();
1633#ifdef GUL17_EXPECTED_EXCEPTIONS_ENABLED
1634 try {
1635 ::new (rhs.valptr()) T(std::move(val()));
1636 val().~T();
1637 ::new (errptr()) unexpected_type(std::move(temp));
1639 } catch (...) {
1640 rhs.err() = std::move(temp);
1641 throw;
1642 }
1643#else
1644 ::new (rhs.valptr()) T(std::move(val()));
1645 val().~T();
1646 ::new (errptr()) unexpected_type(std::move(temp));
1648#endif
1649 }
1650
1651public:
1652 template <class OT = T, class OE = E>
1653 std::enable_if_t<detail::is_swappable<OT>::value &&
1654 detail::is_swappable<OE>::value &&
1655 (std::is_nothrow_move_constructible<OT>::value ||
1656 std::is_nothrow_move_constructible<OE>::value)>
1657 swap(expected &rhs) noexcept(
1658 std::is_nothrow_move_constructible<T>::value
1659 &&detail::is_nothrow_swappable<T>::value
1660 &&std::is_nothrow_move_constructible<E>::value
1661 &&detail::is_nothrow_swappable<E>::value) {
1662 if (has_value() && rhs.has_value()) {
1663 swap_where_both_have_value(rhs, typename std::is_void<T>::type{});
1664 } else if (!has_value() && rhs.has_value()) {
1665 rhs.swap(*this);
1666 } else if (has_value()) {
1667 swap_where_only_one_has_value(rhs, typename std::is_void<T>::type{});
1668 } else {
1669 using std::swap;
1670 swap(err(), rhs.err());
1671 }
1672 }
1673
1674 constexpr const T *operator->() const {
1675 assert(has_value());
1676 return valptr();
1677 }
1678 constexpr T *operator->() {
1679 assert(has_value());
1680 return valptr();
1681 }
1682
1683 template <class U = T,
1684 std::enable_if_t<!std::is_void<U>::value> * = nullptr>
1685 constexpr const U &operator*() const & {
1686 assert(has_value());
1687 return val();
1688 }
1689 template <class U = T,
1690 std::enable_if_t<!std::is_void<U>::value> * = nullptr>
1691 constexpr U &operator*() & {
1692 assert(has_value());
1693 return val();
1694 }
1695 template <class U = T,
1696 std::enable_if_t<!std::is_void<U>::value> * = nullptr>
1697 constexpr const U &&operator*() const && {
1698 assert(has_value());
1699 return std::move(val());
1700 }
1701 template <class U = T,
1702 std::enable_if_t<!std::is_void<U>::value> * = nullptr>
1703 constexpr U &&operator*() && {
1704 assert(has_value());
1705 return std::move(val());
1706 }
1707
1708 constexpr bool has_value() const noexcept { return this->m_has_val; }
1709 constexpr explicit operator bool() const noexcept { return this->m_has_val; }
1710
1711 template <class U = T,
1712 std::enable_if_t<!std::is_void<U>::value> * = nullptr>
1713 constexpr const U &value() const & {
1714 if (!has_value())
1715 detail::throw_exception(bad_expected_access<E>(err().value()));
1716 return val();
1717 }
1718 template <class U = T,
1719 std::enable_if_t<!std::is_void<U>::value> * = nullptr>
1720 constexpr U &value() & {
1721 if (!has_value())
1722 detail::throw_exception(bad_expected_access<E>(err().value()));
1723 return val();
1724 }
1725 template <class U = T,
1726 std::enable_if_t<!std::is_void<U>::value> * = nullptr>
1727 constexpr const U &&value() const && {
1728 if (!has_value())
1729 detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
1730 return std::move(val());
1731 }
1732 template <class U = T,
1733 std::enable_if_t<!std::is_void<U>::value> * = nullptr>
1734 constexpr U &&value() && {
1735 if (!has_value())
1736 detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
1737 return std::move(val());
1738 }
1739
1740 constexpr const E &error() const & {
1741 assert(!has_value());
1742 return err().value();
1743 }
1744 constexpr E &error() & {
1745 assert(!has_value());
1746 return err().value();
1747 }
1748 constexpr const E &&error() const && {
1749 assert(!has_value());
1750 return std::move(err().value());
1751 }
1752 constexpr E &&error() && {
1753 assert(!has_value());
1754 return std::move(err().value());
1755 }
1756
1757 template <class U> constexpr T value_or(U &&v) const & {
1758 static_assert(std::is_copy_constructible<T>::value &&
1759 std::is_convertible<U &&, T>::value,
1760 "T must be copy-constructible and convertible to from U&&");
1761 return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
1762 }
1763 template <class U> constexpr T value_or(U &&v) && {
1764 static_assert(std::is_move_constructible<T>::value &&
1765 std::is_convertible<U &&, T>::value,
1766 "T must be move-constructible and convertible to from U&&");
1767 return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
1768 }
1769};
1770
1771namespace detail {
1772template <class Exp> using exp_t = typename std::decay_t<Exp>::value_type;
1773template <class Exp> using err_t = typename std::decay_t<Exp>::error_type;
1774template <class Exp, class Ret> using ret_t = expected<Ret, err_t<Exp>>;
1775
1776template <class Exp, class F,
1777 std::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
1778 class Ret = decltype(invoke(std::declval<F>(),
1779 *std::declval<Exp>()))>
1780constexpr auto and_then_impl(Exp &&exp, F &&f) {
1781 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
1782
1783 return exp.has_value()
1784 ? invoke(std::forward<F>(f), *std::forward<Exp>(exp))
1785 : Ret(unexpect, std::forward<Exp>(exp).error());
1786}
1787
1788template <class Exp, class F,
1789 std::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
1790 class Ret = decltype(invoke(std::declval<F>()))>
1791constexpr auto and_then_impl(Exp &&exp, F &&f) {
1792 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
1793
1794 return exp.has_value() ? invoke(std::forward<F>(f))
1795 : Ret(unexpect, std::forward<Exp>(exp).error());
1796}
1797
1798template <class Exp, class F,
1799 std::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
1800 class Ret = decltype(invoke(std::declval<F>(),
1801 *std::declval<Exp>())),
1802 std::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
1803constexpr auto expected_map_impl(Exp &&exp, F &&f) {
1805 return exp.has_value() ? result(invoke(std::forward<F>(f),
1806 *std::forward<Exp>(exp)))
1807 : result(unexpect, std::forward<Exp>(exp).error());
1808}
1809
1810template <class Exp, class F,
1811 std::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
1812 class Ret = decltype(invoke(std::declval<F>(),
1813 *std::declval<Exp>())),
1814 std::enable_if_t<std::is_void<Ret>::value> * = nullptr>
1815auto expected_map_impl(Exp &&exp, F &&f) {
1817 if (exp.has_value()) {
1818 invoke(std::forward<F>(f), *std::forward<Exp>(exp));
1819 return result();
1820 }
1821
1822 return result(unexpect, std::forward<Exp>(exp).error());
1823}
1824
1825template <class Exp, class F,
1826 std::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
1827 class Ret = decltype(invoke(std::declval<F>())),
1828 std::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
1829constexpr auto expected_map_impl(Exp &&exp, F &&f) {
1831 return exp.has_value() ? result(invoke(std::forward<F>(f)))
1832 : result(unexpect, std::forward<Exp>(exp).error());
1833}
1834
1835template <class Exp, class F,
1836 std::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
1837 class Ret = decltype(invoke(std::declval<F>())),
1838 std::enable_if_t<std::is_void<Ret>::value> * = nullptr>
1839auto expected_map_impl(Exp &&exp, F &&f) {
1841 if (exp.has_value()) {
1842 invoke(std::forward<F>(f));
1843 return result();
1844 }
1845
1846 return result(unexpect, std::forward<Exp>(exp).error());
1847}
1848
1849template <class Exp, class F,
1850 std::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
1851 class Ret = decltype(invoke(std::declval<F>(),
1852 std::declval<Exp>().error())),
1853 std::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
1854constexpr auto map_error_impl(Exp &&exp, F &&f) {
1855 using result = expected<exp_t<Exp>, std::decay_t<Ret>>;
1856 return exp.has_value()
1857 ? result(*std::forward<Exp>(exp))
1858 : result(unexpect, invoke(std::forward<F>(f),
1859 std::forward<Exp>(exp).error()));
1860}
1861template <class Exp, class F,
1862 std::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
1863 class Ret = decltype(invoke(std::declval<F>(),
1864 std::declval<Exp>().error())),
1865 std::enable_if_t<std::is_void<Ret>::value> * = nullptr>
1866auto map_error_impl(Exp &&exp, F &&f) {
1867 using result = expected<exp_t<Exp>, std::monostate>;
1868 if (exp.has_value()) {
1869 return result(*std::forward<Exp>(exp));
1870 }
1871
1872 invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
1873 return result(unexpect, std::monostate{});
1874}
1875template <class Exp, class F,
1876 std::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
1877 class Ret = decltype(invoke(std::declval<F>(),
1878 std::declval<Exp>().error())),
1879 std::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
1880constexpr auto map_error_impl(Exp &&exp, F &&f) {
1881 using result = expected<exp_t<Exp>, std::decay_t<Ret>>;
1882 return exp.has_value()
1883 ? result()
1884 : result(unexpect, invoke(std::forward<F>(f),
1885 std::forward<Exp>(exp).error()));
1886}
1887template <class Exp, class F,
1888 std::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
1889 class Ret = decltype(invoke(std::declval<F>(),
1890 std::declval<Exp>().error())),
1891 std::enable_if_t<std::is_void<Ret>::value> * = nullptr>
1892auto map_error_impl(Exp &&exp, F &&f) {
1893 using result = expected<exp_t<Exp>, std::monostate>;
1894 if (exp.has_value()) {
1895 return result();
1896 }
1897
1898 invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
1899 return result(unexpect, std::monostate{});
1900}
1901
1902template <class Exp, class F,
1903 class Ret = decltype(invoke(std::declval<F>(),
1904 std::declval<Exp>().error())),
1905 std::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
1906constexpr auto or_else_impl(Exp &&exp, F &&f) {
1907 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
1908 return exp.has_value() ? std::forward<Exp>(exp)
1909 : invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
1910}
1911
1912template <class Exp, class F,
1913 class Ret = decltype(invoke(std::declval<F>(),
1914 std::declval<Exp>().error())),
1915 std::enable_if_t<std::is_void<Ret>::value> * = nullptr>
1916std::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
1917 return exp.has_value() ? std::forward<Exp>(exp)
1918 : (invoke(std::forward<F>(f), std::forward<Exp>(exp).error()),
1919 std::forward<Exp>(exp));
1920}
1921
1922} // namespace detail
1923
1924template <class T, class E, class U, class F>
1925constexpr bool operator==(const expected<T, E> &lhs,
1926 const expected<U, F> &rhs) {
1927 return (lhs.has_value() != rhs.has_value())
1928 ? false
1929 : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
1930}
1931template <class T, class E, class U, class F>
1932constexpr bool operator!=(const expected<T, E> &lhs,
1933 const expected<U, F> &rhs) {
1934 return (lhs.has_value() != rhs.has_value())
1935 ? true
1936 : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs);
1937}
1938template <class E, class F>
1939constexpr bool operator==(const expected<void, E> &lhs,
1940 const expected<void, F> &rhs) {
1941 return (lhs.has_value() != rhs.has_value())
1942 ? false
1943 : (!lhs.has_value() ? lhs.error() == rhs.error() : true);
1944}
1945template <class E, class F>
1946constexpr bool operator!=(const expected<void, E> &lhs,
1947 const expected<void, F> &rhs) {
1948 return (lhs.has_value() != rhs.has_value())
1949 ? true
1950 : (!lhs.has_value() ? lhs.error() == rhs.error() : false);
1951}
1952
1953template <class T, class E, class U>
1954constexpr bool operator==(const expected<T, E> &x, const U &v) {
1955 return x.has_value() ? *x == v : false;
1956}
1957template <class T, class E, class U>
1958constexpr bool operator==(const U &v, const expected<T, E> &x) {
1959 return x.has_value() ? *x == v : false;
1960}
1961template <class T, class E, class U>
1962constexpr bool operator!=(const expected<T, E> &x, const U &v) {
1963 return x.has_value() ? *x != v : true;
1964}
1965template <class T, class E, class U>
1966constexpr bool operator!=(const U &v, const expected<T, E> &x) {
1967 return x.has_value() ? *x != v : true;
1968}
1969
1970template <class T, class E>
1971constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) {
1972 return x.has_value() ? false : x.error() == e.value();
1973}
1974template <class T, class E>
1975constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) {
1976 return x.has_value() ? false : x.error() == e.value();
1977}
1978template <class T, class E>
1979constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) {
1980 return x.has_value() ? true : x.error() != e.value();
1981}
1982template <class T, class E>
1983constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
1984 return x.has_value() ? true : x.error() != e.value();
1985}
1986
1987template <class T, class E,
1988 std::enable_if_t<(std::is_void<T>::value ||
1989 std::is_move_constructible<T>::value) &&
1990 detail::is_swappable<T>::value &&
1991 std::is_move_constructible<E>::value &&
1992 detail::is_swappable<E>::value> * = nullptr>
1993void swap(expected<T, E> &lhs,
1994 expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
1995 lhs.swap(rhs);
1996}
1997
1999
2001
2002} // namespace gul17
2003
2004#endif
The exception thrown by gul17::expected if value() is called, but no value is present.
Definition expected.h:55
An expected<T, E> is an object that normally contains an "expected" object of type T,...
Definition expected.h:93
Class template for constructing the unexpected value of an expected object.
Definition expected.h:101
void swap(SmallVector< ElementT, in_capacity > &a, SmallVector< ElementT, in_capacity > &b)
Exchange the contents of one SmallVector with those of another one.
Definition SmallVector.h:1656
auto constexpr bit_set(unsigned bit) noexcept -> ReturnT
Set a bit in an integral type.
Definition bit_manip.h:121
constexpr auto get(span< E, S > s) -> decltype(s[N])
Return a reference to the Nth element of a given span.
Definition span.h:537
Namespace gul17 contains all functions and classes of the General Utility Library.
Definition doxygen.h:26
Some metaprogramming traits for the General Utility Library.