Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qexpected_p.h
Go to the documentation of this file.
1// Copyright (C) 2017 Sy Brand (tartanllama@gmail.com, @TartanLlama)
2// SPDX-License-Identifier: CC0-1.0
3
4///
5// expected - An implementation of std::expected with extensions
6// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
7//
8// Documentation available at http://tl.tartanllama.xyz/
9//
10// To the extent possible under law, the author(s) have dedicated all
11// copyright and related and neighboring rights to this software to the
12// public domain worldwide. This software is distributed without any warranty.
13//
14// You should have received a copy of the CC0 Public Domain Dedication
15// along with this software. If not, see
16// <http://creativecommons.org/publicdomain/zero/1.0/>.
17///
18// Qt-Security score:significant reason:default
19
20#ifndef Q23_TL_EXPECTED_HPP
21#define Q23_TL_EXPECTED_HPP
22
23//
24// W A R N I N G
25// -------------
26//
27// This file is not part of the Qt API. It exists purely as an
28// implementation detail. This header file may change from version to
29// version without notice, or even be removed.
30//
31// We mean it.
32//
33
34#define Q23_TL_EXPECTED_VERSION_MAJOR 1
35#define Q23_TL_EXPECTED_VERSION_MINOR 1
36#define Q23_TL_EXPECTED_VERSION_PATCH 0
37
38#include <QtCore/private/qglobal_p.h>
39#include <QtCore/qassert.h>
40#include <QtCore/qtconfiginclude.h>
41#include <QtCore/qtconfigmacros.h>
42
43#include <exception>
44#include <functional>
45#include <type_traits>
46#include <utility>
47
48#define Q23_TL_ASSERT Q_ASSERT
49
50#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
51#define Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
52#endif
53
54#if defined(Q23_TL_EXPECTED_EXCEPTIONS_ENABLED) && defined(QT_NO_EXCEPTIONS)
55# undef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
56#endif
57
58#if (defined(_MSC_VER) && _MSC_VER == 1900)
59#define Q23_TL_EXPECTED_MSVC2015
60#define Q23_TL_EXPECTED_MSVC2015_CONSTEXPR
61#else
62#define Q23_TL_EXPECTED_MSVC2015_CONSTEXPR constexpr
63#endif
64
65#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 &&
66 !defined(__clang__))
67#define Q23_TL_EXPECTED_GCC49
68#endif
69
70#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 &&
71 !defined(__clang__))
72#define Q23_TL_EXPECTED_GCC54
73#endif
74
75#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 &&
76 !defined(__clang__))
77#define Q23_TL_EXPECTED_GCC55
78#endif
79
80#if !defined(Q23_TL_ASSERT)
81//can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug
82#if (Q23_TL_CPLUSPLUS > 201103L) && !defined(Q23_TL_EXPECTED_GCC49)
83#include <cassert>
84#define Q23_TL_ASSERT(x) assert(x)
85#else
86#define Q23_TL_ASSERT(x)
87#endif
88#endif
89
90#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 &&
91 !defined(__clang__))
92// GCC < 5 doesn't support overloading on const&& for member functions
93
94#define Q23_TL_EXPECTED_NO_CONSTRR
95// GCC < 5 doesn't support some standard C++11 type traits
96#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)
97 std::has_trivial_copy_constructor<T>
98#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T)
99 std::has_trivial_copy_assign<T>
100
101// This one will be different for GCC 5.7 if it's ever supported
102#define Q23_TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)
103 std::is_trivially_destructible<T>
104
105// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks
106// std::vector for non-copyable types
107#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
108#ifndef Q23_TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
109#define Q23_TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
110QT_BEGIN_NAMESPACE
111namespace q23 {
112namespace detail {
113template <class T>
114struct is_trivially_copy_constructible
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} // namespace q23
122QT_END_NAMESPACE
123#endif
124
125#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)
126 q23::detail::is_trivially_copy_constructible<T>
127#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T)
128 std::is_trivially_copy_assignable<T>
129#define Q23_TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)
130 std::is_trivially_destructible<T>
131#else
132#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)
133 std::is_trivially_copy_constructible<T>
134#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T)
135 std::is_trivially_copy_assignable<T>
136#define Q23_TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)
137 std::is_trivially_destructible<T>
138#endif
139
140#ifdef _MSVC_LANG
141#define Q23_TL_CPLUSPLUS _MSVC_LANG
142#else
143#define Q23_TL_CPLUSPLUS __cplusplus
144#endif
145
146#if Q23_TL_CPLUSPLUS > 201103L
147#define Q23_TL_EXPECTED_CXX14
148#endif
149
150#ifdef Q23_TL_EXPECTED_GCC49
151#define Q23_TL_EXPECTED_GCC49_CONSTEXPR
152#else
153#define Q23_TL_EXPECTED_GCC49_CONSTEXPR constexpr
154#endif
155
156#if (Q23_TL_CPLUSPLUS == 201103L || defined(Q23_TL_EXPECTED_MSVC2015) ||
157 defined(Q23_TL_EXPECTED_GCC49))
158#define Q23_TL_EXPECTED_11_CONSTEXPR
159#else
160#define Q23_TL_EXPECTED_11_CONSTEXPR constexpr
161#endif
162
163QT_BEGIN_NAMESPACE
164namespace q23 {
165template <class T, class E> class expected;
166
167#ifndef Q23_TL_MONOSTATE_INPLACE_MUTEX
168#define Q23_TL_MONOSTATE_INPLACE_MUTEX
169class monostate {};
170
172 explicit in_place_t() = default;
173};
174static constexpr in_place_t in_place{};
175#endif
176
177template <class E> class unexpected {
178public:
179 static_assert(!std::is_same<E, void>::value, "E must not be void");
180
181 unexpected() = delete;
182 constexpr explicit unexpected(const E &e) : m_val(e) {}
183
184 constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {}
185
186 template <class... Args, typename std::enable_if<std::is_constructible<
187 E, Args &&...>::value>::type * = nullptr>
188 constexpr explicit unexpected(in_place_t, Args &&...args)
189 : m_val(std::forward<Args>(args)...) {}
190
191 template <
192 class U, class... Args,
193 typename std::enable_if<std::is_constructible<
194 E, std::initializer_list<U> &, Args &&...>::value>::type * = nullptr>
195 constexpr explicit unexpected(in_place_t, std::initializer_list<U> l,
196 Args &&...args)
197 : m_val(l, std::forward<Args>(args)...) {}
198
199 constexpr const E &error() const & { return m_val; }
200 Q23_TL_EXPECTED_11_CONSTEXPR E &error() & { return m_val; }
201 Q23_TL_EXPECTED_11_CONSTEXPR E &&error() && { return std::move(m_val); }
202 constexpr const E &&error() const && { return std::move(m_val); }
203
204private:
205 E m_val;
206};
207
208#ifdef __cpp_deduction_guides
209template <class E> unexpected(E) -> unexpected<E>;
210#endif
211
212template <class E>
213constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) {
214 return lhs.error() == rhs.error();
215}
216template <class E>
217constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
218 return lhs.error() != rhs.error();
219}
220template <class E>
221constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) {
222 return lhs.error() < rhs.error();
223}
224template <class E>
225constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
226 return lhs.error() <= rhs.error();
227}
228template <class E>
229constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
230 return lhs.error() > rhs.error();
231}
232template <class E>
233constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
234 return lhs.error() >= rhs.error();
235}
236
237template <class E>
238unexpected<typename std::decay<E>::type> make_unexpected(E &&e) {
239 return unexpected<typename std::decay<E>::type>(std::forward<E>(e));
240}
241
243 unexpect_t() = default;
244};
245static constexpr unexpect_t unexpect{};
246
247namespace detail {
248template <typename E>
250#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
251 throw std::forward<E>(e);
252#else
253 (void)e;
254#ifdef _MSC_VER
255 __assume(0);
256#else
257 Q_UNREACHABLE();
258#endif
259#endif
260}
261
262#ifndef Q23_TL_TRAITS_MUTEX
263#define Q23_TL_TRAITS_MUTEX
264// C++14-style aliases for brevity
265template <class T> using remove_const_t = typename std::remove_const<T>::type;
266template <class T>
267using remove_reference_t = typename std::remove_reference<T>::type;
268template <class T> using decay_t = typename std::decay<T>::type;
269template <bool E, class T = void>
270using enable_if_t = typename std::enable_if<E, T>::type;
271template <bool B, class T, class F>
272using conditional_t = typename std::conditional<B, T, F>::type;
273
274// std::conjunction from C++17
275template <class...> struct conjunction : std::true_type {};
276template <class B> struct conjunction<B> : B {};
277template <class B, class... Bs>
278struct conjunction<B, Bs...>
279 : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
280
281#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
282#define Q23_TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
283#endif
284
285// In C++11 mode, there's an issue in libc++'s std::mem_fn
286// which results in a hard-error when using it in a noexcept expression
287// in some cases. This is a check to workaround the common failing case.
288#ifdef Q23_TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
289template <class T>
291template <class T, class Ret, class... Args>
293 : std::true_type {};
294template <class T, class Ret, class... Args>
296 : std::true_type {};
297template <class T, class Ret, class... Args>
299 : std::true_type {};
300template <class T, class Ret, class... Args>
301struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile>
302 : std::true_type {};
303template <class T, class Ret, class... Args>
304struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &>
305 : std::true_type {};
306template <class T, class Ret, class... Args>
307struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &&>
308 : std::true_type {};
309
310template <class T> struct is_const_or_const_ref : std::false_type {};
311template <class T> struct is_const_or_const_ref<T const &> : std::true_type {};
312template <class T> struct is_const_or_const_ref<T const> : std::true_type {};
313#endif
314
315// std::invoke from C++17
316// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
317template <
318 typename Fn, typename... Args,
319#ifdef Q23_TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
322#endif
323 typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0>
324constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
325 noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
326 -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
327 return std::mem_fn(f)(std::forward<Args>(args)...);
328}
329
330template <typename Fn, typename... Args,
332constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
333 noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
334 -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
335 return std::forward<Fn>(f)(std::forward<Args>(args)...);
336}
337
338// std::invoke_result from C++17
339template <class F, class, class... Us> struct invoke_result_impl;
340
341template <class F, class... Us>
343 F,
344 decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
345 Us...> {
346 using type =
347 decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
348};
349
350template <class F, class... Us>
351using invoke_result = invoke_result_impl<F, void, Us...>;
352
353template <class F, class... Us>
354using invoke_result_t = typename invoke_result<F, Us...>::type;
355
356#if defined(_MSC_VER) && _MSC_VER <= 1900
357// TODO make a version which works with MSVC 2015
358template <class T, class U = T> struct is_swappable : std::true_type {};
359
360template <class T, class U = T> struct is_nothrow_swappable : std::true_type {};
361#else
362// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
363namespace swap_adl_tests {
364// if swap ADL finds this then it would call std::swap otherwise (same
365// signature)
366struct tag {};
367
368template <class T> tag swap(T &, T &);
369template <class T, std::size_t N> tag swap(T (&a)[N], T (&b)[N]);
370
371// helper functions to test if an unqualified swap is possible, and if it
372// becomes std::swap
373template <class, class> std::false_type can_swap(...) noexcept(false);
374template <class T, class U,
375 class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
376std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
377 std::declval<U &>())));
378
379template <class, class> std::false_type uses_std(...);
380template <class T, class U>
381std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
383
384template <class T>
389
390template <class T, std::size_t N>
392
393template <class T, class U>
395 : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
396} // namespace swap_adl_tests
397
398template <class T, class U = T>
401 bool,
402 decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
403 (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
406
407template <class T, std::size_t N>
408struct is_swappable<T[N], T[N]>
410 bool,
411 decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
412 (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(
413 0))::value ||
414 is_swappable<T, T>::value)> {};
415
416template <class T, class U = T>
425#endif
426#endif
427
428// Trait for checking if a type is a q23::expected
429template <class T> struct is_expected_impl : std::false_type {};
430template <class T, class E>
432template <class T> using is_expected = is_expected_impl<decay_t<T>>;
433
434template <class T, class E, class U>
436 std::is_constructible<T, U &&>::value &&
440
441template <class T, class E, class U, class G, class UR, class GR>
446 !std::is_constructible<T, expected<U, G> &&>::value &&
447 !std::is_constructible<T, const expected<U, G> &>::value &&
448 !std::is_constructible<T, const expected<U, G> &&>::value &&
449 !std::is_convertible<expected<U, G> &, T>::value &&
450 !std::is_convertible<expected<U, G> &&, T>::value &&
451 !std::is_convertible<const expected<U, G> &, T>::value &&
452 !std::is_convertible<const expected<U, G> &&, T>::value>;
453
454template <class T, class U>
456
457template <class T>
460
461template <class T>
464
465template <class T>
467
468template <class T>
470
471} // namespace detail
472
473namespace detail {
474struct no_init_t {};
475static constexpr no_init_t no_init{};
476
477// Implements the storage of the values, and ensures that the destructor is
478// trivial if it can be.
479//
480// This specialization is for where neither `T` or `E` is trivially
481// destructible, so the destructors must be called on destruction of the
482// `expected`
483template <class T, class E, bool = std::is_trivially_destructible<T>::value,
484 bool = std::is_trivially_destructible<E>::value>
486 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
488
489 template <class... Args,
490 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
491 nullptr>
492 constexpr expected_storage_base(in_place_t, Args &&...args)
493 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
494
495 template <class U, class... Args,
496 detail::enable_if_t<std::is_constructible<
497 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
498 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
499 Args &&...args)
500 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
501 template <class... Args,
502 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
503 nullptr>
504 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
505 : m_unexpect(in_place, std::forward<Args>(args)...), m_has_val(false) {}
506
507 template <class U, class... Args,
508 detail::enable_if_t<std::is_constructible<
509 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
511 std::initializer_list<U> il,
512 Args &&...args)
513 : m_unexpect(in_place, il, std::forward<Args>(args)...), m_has_val(false) {}
514
516 if (m_has_val) {
517 m_val.~T();
518 } else {
519 m_unexpect.~unexpected<E>();
520 }
521 }
522 union {
526 };
528};
529
530// This specialization is for when both `T` and `E` are trivially-destructible,
531// so the destructor of the `expected` can be trivial.
532template <class T, class E> struct expected_storage_base<T, E, true, true> {
533 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
535
536 template <class... Args,
537 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
538 nullptr>
539 constexpr expected_storage_base(in_place_t, Args &&...args)
540 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
541
542 template <class U, class... Args,
543 detail::enable_if_t<std::is_constructible<
544 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
545 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
546 Args &&...args)
547 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
548 template <class... Args,
549 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
550 nullptr>
551 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
552 : m_unexpect(in_place, std::forward<Args>(args)...), m_has_val(false) {}
553
554 template <class U, class... Args,
555 detail::enable_if_t<std::is_constructible<
556 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
558 std::initializer_list<U> il,
559 Args &&...args)
560 : m_unexpect(in_place, il, std::forward<Args>(args)...), m_has_val(false) {}
561
567 union {
571 };
573};
574
575// T is trivial, E is not.
576template <class T, class E> struct expected_storage_base<T, E, true, false> {
577 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
580
581 template <class... Args,
582 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
583 nullptr>
584 constexpr expected_storage_base(in_place_t, Args &&...args)
585 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
586
587 template <class U, class... Args,
588 detail::enable_if_t<std::is_constructible<
589 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
590 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
591 Args &&...args)
592 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
593 template <class... Args,
594 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
595 nullptr>
596 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
597 : m_unexpect(in_place, std::forward<Args>(args)...), m_has_val(false) {}
598
599 template <class U, class... Args,
600 detail::enable_if_t<std::is_constructible<
601 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
603 std::initializer_list<U> il,
604 Args &&...args)
605 : m_unexpect(in_place, il, std::forward<Args>(args)...), m_has_val(false) {}
606
612 if (!m_has_val) {
613 m_unexpect.~unexpected<E>();
614 }
615 }
616
617 union {
621 };
623};
624
625// E is trivial, T is not.
626template <class T, class E> struct expected_storage_base<T, E, false, true> {
627 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
629
630 template <class... Args,
631 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
632 nullptr>
633 constexpr expected_storage_base(in_place_t, Args &&...args)
634 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
635
636 template <class U, class... Args,
637 detail::enable_if_t<std::is_constructible<
638 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
639 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
640 Args &&...args)
641 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
642 template <class... Args,
643 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
644 nullptr>
645 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
646 : m_unexpect(in_place, std::forward<Args>(args)...), m_has_val(false) {}
647
648 template <class U, class... Args,
649 detail::enable_if_t<std::is_constructible<
650 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
652 std::initializer_list<U> il,
653 Args &&...args)
654 : m_unexpect(in_place, il, std::forward<Args>(args)...),
655 m_has_val(false) {}
656
662 if (m_has_val) {
663 m_val.~T();
664 }
665 }
666 union {
670 };
672};
673
674// `T` is `void`, `E` is trivially-destructible
675template <class E> struct expected_storage_base<void, E, false, true> {
676 #if __GNUC__ <= 5
677 //no constexpr for GCC 4/5 bug
678 #else
680 #endif
682
684
686
687 template <class... Args,
688 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
689 nullptr>
690 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
691 : m_unexpect(in_place, std::forward<Args>(args)...), m_has_val(false) {}
692
693 template <class U, class... Args,
694 detail::enable_if_t<std::is_constructible<
695 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
697 std::initializer_list<U> il,
698 Args &&...args)
699 : m_unexpect(in_place, il, std::forward<Args>(args)...), m_has_val(false) {}
700
706 struct dummy {};
707 union {
710 };
712};
713
714// `T` is `void`, `E` is not trivially-destructible
715template <class E> struct expected_storage_base<void, E, false, false> {
716 constexpr expected_storage_base() : m_dummy(), m_has_val(true) {}
718
720
721 template <class... Args,
722 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
723 nullptr>
724 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
725 : m_unexpect(in_place, std::forward<Args>(args)...), m_has_val(false) {}
726
727 template <class U, class... Args,
728 detail::enable_if_t<std::is_constructible<
729 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
731 std::initializer_list<U> il,
732 Args &&...args)
733 : m_unexpect(in_place, il, std::forward<Args>(args)...), m_has_val(false) {}
734
740 if (!m_has_val) {
741 m_unexpect.~unexpected<E>();
742 }
743 }
744
745 union {
748 };
750};
751
752// This base class provides some handy member functions which can be used in
753// further derived classes
754template <class T, class E>
757
758 template <class... Args> void construct(Args &&...args) noexcept {
759 new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
760 this->m_has_val = true;
761 }
762
763 template <class Rhs> void construct_with(Rhs &&rhs) noexcept {
764 new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
765 this->m_has_val = true;
766 }
767
768 template <class... Args> void construct_error(Args &&...args) noexcept {
769 new (std::addressof(this->m_unexpect))
770 unexpected<E>(std::forward<Args>(args)...);
771 this->m_has_val = false;
772 }
773
774#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
775
776 // These assign overloads ensure that the most efficient assignment
777 // implementation is used while maintaining the strong exception guarantee.
778 // The problematic case is where rhs has a value, but *this does not.
779 //
780 // This overload handles the case where we can just copy-construct `T`
781 // directly into place without throwing.
782 template <class U = T,
783 detail::enable_if_t<std::is_nothrow_copy_constructible<U>::value>
784 * = nullptr>
785 void assign(const expected_operations_base &rhs) noexcept {
786 if (!this->m_has_val && rhs.m_has_val) {
787 geterr().~unexpected<E>();
788 construct(rhs.get());
789 } else {
790 assign_common(rhs);
791 }
792 }
793
794 // This overload handles the case where we can attempt to create a copy of
795 // `T`, then no-throw move it into place if the copy was successful.
796 template <class U = T,
797 detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
798 std::is_nothrow_move_constructible<U>::value>
799 * = nullptr>
800 void assign(const expected_operations_base &rhs) noexcept {
801 if (!this->m_has_val && rhs.m_has_val) {
802 T tmp = rhs.get();
803 geterr().~unexpected<E>();
804 construct(std::move(tmp));
805 } else {
806 assign_common(rhs);
807 }
808 }
809
810 // This overload is the worst-case, where we have to move-construct the
811 // unexpected value into temporary storage, then try to copy the T into place.
812 // If the construction succeeds, then everything is fine, but if it throws,
813 // then we move the old unexpected value back into place before rethrowing the
814 // exception.
815 template <class U = T,
816 detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
817 !std::is_nothrow_move_constructible<U>::value>
818 * = nullptr>
819 void assign(const expected_operations_base &rhs) {
820 if (!this->m_has_val && rhs.m_has_val) {
821 auto tmp = std::move(geterr());
822 geterr().~unexpected<E>();
823
824#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
825 try {
826 construct(rhs.get());
827 } catch (...) {
828 geterr() = std::move(tmp);
829 throw;
830 }
831#else
832 construct(rhs.get());
833#endif
834 } else {
835 assign_common(rhs);
836 }
837 }
838
839 // These overloads do the same as above, but for rvalues
840 template <class U = T,
841 detail::enable_if_t<std::is_nothrow_move_constructible<U>::value>
842 * = nullptr>
843 void assign(expected_operations_base &&rhs) noexcept {
844 if (!this->m_has_val && rhs.m_has_val) {
845 geterr().~unexpected<E>();
846 construct(std::move(rhs).get());
847 } else {
848 assign_common(std::move(rhs));
849 }
850 }
851
852 template <class U = T,
853 detail::enable_if_t<!std::is_nothrow_move_constructible<U>::value>
854 * = nullptr>
855 void assign(expected_operations_base &&rhs) {
856 if (!this->m_has_val && rhs.m_has_val) {
857 auto tmp = std::move(geterr());
858 geterr().~unexpected<E>();
859#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
860 try {
861 construct(std::move(rhs).get());
862 } catch (...) {
863 geterr() = std::move(tmp);
864 throw;
865 }
866#else
867 construct(std::move(rhs).get());
868#endif
869 } else {
870 assign_common(std::move(rhs));
871 }
872 }
873
874#else
875
876 // If exceptions are disabled then we can just copy-construct
877 void assign(const expected_operations_base &rhs) noexcept {
878 if (!this->m_has_val && rhs.m_has_val) {
879 geterr().~unexpected<E>();
880 construct(rhs.get());
881 } else {
883 }
884 }
885
887 if (!this->m_has_val && rhs.m_has_val) {
888 geterr().~unexpected<E>();
889 construct(std::move(rhs).get());
890 } else {
892 }
893 }
894
895#endif
896
897 // The common part of move/copy assigning
898 template <class Rhs> void assign_common(Rhs &&rhs) {
899 if (this->m_has_val) {
900 if (rhs.m_has_val) {
901 get() = std::forward<Rhs>(rhs).get();
902 } else {
904 construct_error(std::forward<Rhs>(rhs).geterr());
905 }
906 } else {
907 if (!rhs.m_has_val) {
908 geterr() = std::forward<Rhs>(rhs).geterr();
909 }
910 }
911 }
912
913 bool has_value() const { return this->m_has_val; }
914
915 Q23_TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
916 constexpr const T &get() const & { return this->m_val; }
917 Q23_TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
918#ifndef Q23_TL_EXPECTED_NO_CONSTRR
919 constexpr const T &&get() const && { return std::move(this->m_val); }
920#endif
921
923 return this->m_unexpect;
924 }
925 constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
927 return std::move(this->m_unexpect);
928 }
929#ifndef Q23_TL_EXPECTED_NO_CONSTRR
930 constexpr const unexpected<E> &&geterr() const && {
931 return std::move(this->m_unexpect);
932 }
933#endif
934
936};
937
938// This base class provides some handy member functions which can be used in
939// further derived classes
940template <class E>
943
944 template <class... Args> void construct() noexcept { this->m_has_val = true; }
945
946 // This function doesn't use its argument, but needs it so that code in
947 // levels above this can work independently of whether T is void
948 template <class Rhs> void construct_with(Rhs &&) noexcept {
949 this->m_has_val = true;
950 }
951
952 template <class... Args> void construct_error(Args &&...args) noexcept {
953 new (std::addressof(this->m_unexpect))
954 unexpected<E>(std::forward<Args>(args)...);
955 this->m_has_val = false;
956 }
957
958 template <class Rhs> void assign(Rhs &&rhs) noexcept {
959 if (!this->m_has_val) {
960 if (rhs.m_has_val) {
961 geterr().~unexpected<E>();
962 construct();
963 } else {
964 geterr() = std::forward<Rhs>(rhs).geterr();
965 }
966 } else {
967 if (!rhs.m_has_val) {
968 construct_error(std::forward<Rhs>(rhs).geterr());
969 }
970 }
971 }
972
973 bool has_value() const { return this->m_has_val; }
974
976 return this->m_unexpect;
977 }
978 constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
980 return std::move(this->m_unexpect);
981 }
982#ifndef Q23_TL_EXPECTED_NO_CONSTRR
983 constexpr const unexpected<E> &&geterr() const && {
984 return std::move(this->m_unexpect);
985 }
986#endif
987
989 // no-op
990 }
991};
992
993// This class manages conditionally having a trivial copy constructor
994// This specialization is for when T and E are trivially copy constructible
995template <class T, class E,
1003
1004// This specialization is for when T or E are non-trivially copy constructible
1005template <class T, class E>
1006struct expected_copy_base<T, E, false, true> : expected_operations_base<T, E> {
1008
1012 if (rhs.has_value()) {
1013 this->construct_with(rhs);
1014 } else {
1015 this->construct_error(rhs.geterr());
1016 }
1017 }
1018
1022};
1023
1024// This class manages conditionally having a trivial move constructor
1025// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
1026// doesn't implement an analogue to std::is_trivially_move_constructible. We
1027// have to make do with a non-trivial move constructor even if T is trivially
1028// move constructible
1029#ifndef Q23_TL_EXPECTED_GCC49
1030template <class T, class E,
1036#else
1037template <class T, class E, bool = false> struct expected_move_base;
1038#endif
1039template <class T, class E>
1040struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
1042
1045
1049 if (rhs.has_value()) {
1050 this->construct_with(std::move(rhs));
1051 } else {
1052 this->construct_error(std::move(rhs.geterr()));
1053 }
1054 }
1057};
1058
1059// This class manages conditionally having a trivial copy assignment operator
1060template <class T, class E,
1061 bool = is_void_or<
1075
1076template <class T, class E>
1091
1092// This class manages conditionally having a trivial move assignment operator
1093// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
1094// doesn't implement an analogue to std::is_trivially_move_assignable. We have
1095// to make do with a non-trivial move assignment operator even if T is trivially
1096// move assignable
1097#ifndef Q23_TL_EXPECTED_GCC49
1098template <class T, class E,
1099 bool =
1109#else
1110template <class T, class E, bool = false> struct expected_move_assign_base;
1111#endif
1112
1113template <class T, class E>
1134
1135// expected_delete_ctor_base will conditionally delete copy and move
1136// constructors depending on whether T is copy/move constructible
1137template <class T, class E,
1138 bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
1140 bool EnableMove = (is_move_constructible_or_void<T>::value &&
1151
1152template <class T, class E>
1162
1163template <class T, class E>
1173
1174template <class T, class E>
1184
1185// expected_delete_assign_base will conditionally delete copy and move
1186// constructors depending on whether T and E are copy/move constructible +
1187// assignable
1188template <class T, class E,
1189 bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
1193 bool EnableMove = (is_move_constructible_or_void<T>::value &&
1207
1208template <class T, class E>
1219
1220template <class T, class E>
1231
1232template <class T, class E>
1243
1244// This is needed to be able to construct the expected_default_ctor_base which
1245// follows, while still conditionally deleting the default constructor.
1247 explicit constexpr default_constructor_tag() = default;
1248};
1249
1250// expected_default_ctor_base will ensure that expected has a deleted default
1251// constructor if T is not default constructible.
1252// This specialization is for when T is default constructible
1253template <class T, class E,
1254 bool Enable =
1255 std::is_default_constructible<T>::value || std::is_void<T>::value>
1257 constexpr expected_default_ctor_base() noexcept = default;
1259 expected_default_ctor_base const &) noexcept = default;
1261 default;
1263 operator=(expected_default_ctor_base const &) noexcept = default;
1265 operator=(expected_default_ctor_base &&) noexcept = default;
1266
1268};
1269
1270// This specialization is for when T is not default constructible
1271template <class T, class E> struct expected_default_ctor_base<T, E, false> {
1272 constexpr expected_default_ctor_base() noexcept = delete;
1274 expected_default_ctor_base const &) noexcept = default;
1276 default;
1278 operator=(expected_default_ctor_base const &) noexcept = default;
1280 operator=(expected_default_ctor_base &&) noexcept = default;
1281
1283};
1284} // namespace detail
1285
1286template <class E> class bad_expected_access : public std::exception {
1287public:
1288 explicit bad_expected_access(E e) : m_val(std::move(e)) {}
1289
1290 virtual const char *what() const noexcept override {
1291 return "Bad expected access";
1292 }
1293
1294 const E &error() const & { return m_val; }
1295 E &error() & { return m_val; }
1296 const E &&error() const && { return std::move(m_val); }
1297 E &&error() && { return std::move(m_val); }
1298
1299private:
1300 E m_val;
1301};
1302
1303/// An `expected<T, E>` object is an object that contains the storage for
1304/// another object and manages the lifetime of this contained object `T`.
1305/// Alternatively it could contain the storage for another unexpected object
1306/// `E`. The contained object may not be initialized after the expected object
1307/// has been initialized, and may not be destroyed before the expected object
1308/// has been destroyed. The initialization state of the contained object is
1309/// tracked by the expected object.
1310template <class T, class E>
1315 static_assert(!std::is_reference<T>::value, "T must not be a reference");
1316 static_assert(!std::is_same<T, std::remove_cv<in_place_t>::type>::value,
1317 "T must not be in_place_t");
1318 static_assert(!std::is_same<T, std::remove_cv<unexpect_t>::type>::value,
1319 "T must not be unexpect_t");
1320 static_assert(
1321 !std::is_same<T, typename std::remove_cv<unexpected<E>>::type>::value,
1322 "T must not be unexpected<E>");
1323 static_assert(!std::is_reference<E>::value, "E must not be a reference");
1324
1325 T *valptr() { return std::addressof(this->m_val); }
1326 const T *valptr() const { return std::addressof(this->m_val); }
1327 unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
1328 const unexpected<E> *errptr() const {
1329 return std::addressof(this->m_unexpect);
1330 }
1331
1332 template <class U = T,
1333 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1335 return this->m_val;
1336 }
1337 Q23_TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }
1338
1339 template <class U = T,
1340 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1341 constexpr const U &val() const {
1342 return this->m_val;
1343 }
1344 constexpr const unexpected<E> &err() const { return this->m_unexpect; }
1345
1348
1349public:
1350 typedef T value_type;
1351 typedef E error_type;
1353
1354#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) &&
1355 !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
1356 template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
1357 return and_then_impl(*this, std::forward<F>(f));
1358 }
1359 template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
1360 return and_then_impl(std::move(*this), std::forward<F>(f));
1361 }
1362 template <class F> constexpr auto and_then(F &&f) const & {
1363 return and_then_impl(*this, std::forward<F>(f));
1364 }
1365
1366#ifndef Q23_TL_EXPECTED_NO_CONSTRR
1367 template <class F> constexpr auto and_then(F &&f) const && {
1368 return and_then_impl(std::move(*this), std::forward<F>(f));
1369 }
1370#endif
1371
1372#else
1373 template <class F>
1375 and_then(F &&f) & -> decltype(and_then_impl(std::declval<expected &>(),
1376 std::forward<F>(f))) {
1377 return and_then_impl(*this, std::forward<F>(f));
1378 }
1379 template <class F>
1381 and_then(F &&f) && -> decltype(and_then_impl(std::declval<expected &&>(),
1382 std::forward<F>(f))) {
1383 return and_then_impl(std::move(*this), std::forward<F>(f));
1384 }
1385 template <class F>
1386 constexpr auto and_then(F &&f) const & -> decltype(and_then_impl(
1387 std::declval<expected const &>(), std::forward<F>(f))) {
1388 return and_then_impl(*this, std::forward<F>(f));
1389 }
1390
1391#ifndef Q23_TL_EXPECTED_NO_CONSTRR
1392 template <class F>
1393 constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(
1394 std::declval<expected const &&>(), std::forward<F>(f))) {
1395 return and_then_impl(std::move(*this), std::forward<F>(f));
1396 }
1397#endif
1398#endif
1399
1400#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) &&
1401 !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
1402 template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
1403 return expected_map_impl(*this, std::forward<F>(f));
1404 }
1405 template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
1406 return expected_map_impl(std::move(*this), std::forward<F>(f));
1407 }
1408 template <class F> constexpr auto map(F &&f) const & {
1409 return expected_map_impl(*this, std::forward<F>(f));
1410 }
1411 template <class F> constexpr auto map(F &&f) const && {
1412 return expected_map_impl(std::move(*this), std::forward<F>(f));
1413 }
1414#else
1415 template <class F>
1417 std::declval<expected &>(), std::declval<F &&>()))
1418 map(F &&f) & {
1419 return expected_map_impl(*this, std::forward<F>(f));
1420 }
1421 template <class F>
1423 std::declval<F &&>()))
1424 map(F &&f) && {
1425 return expected_map_impl(std::move(*this), std::forward<F>(f));
1426 }
1427 template <class F>
1428 constexpr decltype(expected_map_impl(std::declval<const expected &>(),
1429 std::declval<F &&>()))
1430 map(F &&f) const & {
1431 return expected_map_impl(*this, std::forward<F>(f));
1432 }
1433
1434#ifndef Q23_TL_EXPECTED_NO_CONSTRR
1435 template <class F>
1436 constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
1437 std::declval<F &&>()))
1438 map(F &&f) const && {
1439 return expected_map_impl(std::move(*this), std::forward<F>(f));
1440 }
1441#endif
1442#endif
1443
1444#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) &&
1445 !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
1446 template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & {
1447 return expected_map_impl(*this, std::forward<F>(f));
1448 }
1449 template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && {
1450 return expected_map_impl(std::move(*this), std::forward<F>(f));
1451 }
1452 template <class F> constexpr auto transform(F &&f) const & {
1453 return expected_map_impl(*this, std::forward<F>(f));
1454 }
1455 template <class F> constexpr auto transform(F &&f) const && {
1456 return expected_map_impl(std::move(*this), std::forward<F>(f));
1457 }
1458#else
1459 template <class F>
1461 std::declval<expected &>(), std::declval<F &&>()))
1463 return expected_map_impl(*this, std::forward<F>(f));
1464 }
1465 template <class F>
1467 std::declval<F &&>()))
1468 transform(F &&f) && {
1469 return expected_map_impl(std::move(*this), std::forward<F>(f));
1470 }
1471 template <class F>
1472 constexpr decltype(expected_map_impl(std::declval<const expected &>(),
1473 std::declval<F &&>()))
1474 transform(F &&f) const & {
1475 return expected_map_impl(*this, std::forward<F>(f));
1476 }
1477
1478#ifndef Q23_TL_EXPECTED_NO_CONSTRR
1479 template <class F>
1480 constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
1481 std::declval<F &&>()))
1482 transform(F &&f) const && {
1483 return expected_map_impl(std::move(*this), std::forward<F>(f));
1484 }
1485#endif
1486#endif
1487
1488#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) &&
1489 !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
1490 template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
1491 return map_error_impl(*this, std::forward<F>(f));
1492 }
1493 template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
1494 return map_error_impl(std::move(*this), std::forward<F>(f));
1495 }
1496 template <class F> constexpr auto map_error(F &&f) const & {
1497 return map_error_impl(*this, std::forward<F>(f));
1498 }
1499 template <class F> constexpr auto map_error(F &&f) const && {
1500 return map_error_impl(std::move(*this), std::forward<F>(f));
1501 }
1502#else
1503 template <class F>
1505 std::declval<F &&>()))
1507 return map_error_impl(*this, std::forward<F>(f));
1508 }
1509 template <class F>
1511 std::declval<F &&>()))
1512 map_error(F &&f) && {
1513 return map_error_impl(std::move(*this), std::forward<F>(f));
1514 }
1515 template <class F>
1516 constexpr decltype(map_error_impl(std::declval<const expected &>(),
1517 std::declval<F &&>()))
1518 map_error(F &&f) const & {
1519 return map_error_impl(*this, std::forward<F>(f));
1520 }
1521
1522#ifndef Q23_TL_EXPECTED_NO_CONSTRR
1523 template <class F>
1524 constexpr decltype(map_error_impl(std::declval<const expected &&>(),
1525 std::declval<F &&>()))
1526 map_error(F &&f) const && {
1527 return map_error_impl(std::move(*this), std::forward<F>(f));
1528 }
1529#endif
1530#endif
1531#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) &&
1532 !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
1533 template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & {
1534 return map_error_impl(*this, std::forward<F>(f));
1535 }
1536 template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && {
1537 return map_error_impl(std::move(*this), std::forward<F>(f));
1538 }
1539 template <class F> constexpr auto transform_error(F &&f) const & {
1540 return map_error_impl(*this, std::forward<F>(f));
1541 }
1542 template <class F> constexpr auto transform_error(F &&f) const && {
1543 return map_error_impl(std::move(*this), std::forward<F>(f));
1544 }
1545#else
1546 template <class F>
1548 std::declval<F &&>()))
1550 return map_error_impl(*this, std::forward<F>(f));
1551 }
1552 template <class F>
1554 std::declval<F &&>()))
1556 return map_error_impl(std::move(*this), std::forward<F>(f));
1557 }
1558 template <class F>
1559 constexpr decltype(map_error_impl(std::declval<const expected &>(),
1560 std::declval<F &&>()))
1561 transform_error(F &&f) const & {
1562 return map_error_impl(*this, std::forward<F>(f));
1563 }
1564
1565#ifndef Q23_TL_EXPECTED_NO_CONSTRR
1566 template <class F>
1567 constexpr decltype(map_error_impl(std::declval<const expected &&>(),
1568 std::declval<F &&>()))
1569 transform_error(F &&f) const && {
1570 return map_error_impl(std::move(*this), std::forward<F>(f));
1571 }
1572#endif
1573#endif
1574 template <class F> expected Q23_TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
1575 return or_else_impl(*this, std::forward<F>(f));
1576 }
1577
1578 template <class F> expected Q23_TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && {
1579 return or_else_impl(std::move(*this), std::forward<F>(f));
1580 }
1581
1582 template <class F> expected constexpr or_else(F &&f) const & {
1583 return or_else_impl(*this, std::forward<F>(f));
1584 }
1585
1586#ifndef Q23_TL_EXPECTED_NO_CONSTRR
1587 template <class F> expected constexpr or_else(F &&f) const && {
1588 return or_else_impl(std::move(*this), std::forward<F>(f));
1589 }
1590#endif
1591 constexpr expected() = default;
1592 constexpr expected(const expected &rhs) = default;
1593 constexpr expected(expected &&rhs) = default;
1594 expected &operator=(const expected &rhs) = default;
1595 expected &operator=(expected &&rhs) = default;
1596
1597 template <class... Args,
1598 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
1599 nullptr>
1600 constexpr expected(in_place_t, Args &&...args)
1603
1604 template <class U, class... Args,
1605 detail::enable_if_t<std::is_constructible<
1606 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1607 constexpr expected(in_place_t, std::initializer_list<U> il, Args &&...args)
1610
1611 template <class G = E,
1612 detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
1613 nullptr,
1614 detail::enable_if_t<!std::is_convertible<const G &, E>::value> * =
1615 nullptr>
1616 explicit constexpr expected(const unexpected<G> &e)
1617 : impl_base(unexpect, e.error()),
1619
1620 template <
1621 class G = E,
1622 detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
1623 nullptr,
1624 detail::enable_if_t<std::is_convertible<const G &, E>::value> * = nullptr>
1625 constexpr expected(unexpected<G> const &e)
1626 : impl_base(unexpect, e.error()),
1628
1629 template <
1630 class G = E,
1631 detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
1632 detail::enable_if_t<!std::is_convertible<G &&, E>::value> * = nullptr>
1633 explicit constexpr expected(unexpected<G> &&e) noexcept(
1635 : impl_base(unexpect, std::move(e.error())),
1637
1638 template <
1639 class G = E,
1640 detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
1641 detail::enable_if_t<std::is_convertible<G &&, E>::value> * = nullptr>
1642 constexpr expected(unexpected<G> &&e) noexcept(
1644 : impl_base(unexpect, std::move(e.error())),
1646
1647 template <class... Args,
1648 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
1649 nullptr>
1650 constexpr explicit expected(unexpect_t, Args &&...args)
1653
1654 template <class U, class... Args,
1655 detail::enable_if_t<std::is_constructible<
1656 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1657 constexpr explicit expected(unexpect_t, std::initializer_list<U> il,
1658 Args &&...args)
1661
1662 template <class U, class G,
1663 detail::enable_if_t<!(std::is_convertible<U const &, T>::value &&
1664 std::is_convertible<G const &, E>::value)> * =
1665 nullptr,
1666 detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
1667 * = nullptr>
1670 if (rhs.has_value()) {
1671 this->construct(*rhs);
1672 } else {
1673 this->construct_error(rhs.error());
1674 }
1675 }
1676
1677 template <class U, class G,
1678 detail::enable_if_t<(std::is_convertible<U const &, T>::value &&
1679 std::is_convertible<G const &, E>::value)> * =
1680 nullptr,
1681 detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
1682 * = nullptr>
1685 if (rhs.has_value()) {
1686 this->construct(*rhs);
1687 } else {
1688 this->construct_error(rhs.error());
1689 }
1690 }
1691
1692 template <
1693 class U, class G,
1694 detail::enable_if_t<!(std::is_convertible<U &&, T>::value &&
1695 std::is_convertible<G &&, E>::value)> * = nullptr,
1696 detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
1699 if (rhs.has_value()) {
1700 this->construct(std::move(*rhs));
1701 } else {
1702 this->construct_error(std::move(rhs.error()));
1703 }
1704 }
1705
1706 template <
1707 class U, class G,
1708 detail::enable_if_t<(std::is_convertible<U &&, T>::value &&
1709 std::is_convertible<G &&, E>::value)> * = nullptr,
1710 detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
1713 if (rhs.has_value()) {
1714 this->construct(std::move(*rhs));
1715 } else {
1716 this->construct_error(std::move(rhs.error()));
1717 }
1718 }
1719
1720 template <
1721 class U = T,
1722 detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,
1723 detail::expected_enable_forward_value<T, E, U> * = nullptr>
1725 : expected(in_place, std::forward<U>(v)) {}
1726
1727 template <
1728 class U = T,
1729 detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr,
1730 detail::expected_enable_forward_value<T, E, U> * = nullptr>
1733
1734 template <
1735 class U = T, class G = T,
1736 detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * =
1737 nullptr,
1738 detail::enable_if_t<!std::is_void<G>::value> * = nullptr,
1739 detail::enable_if_t<
1740 (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
1741 !detail::conjunction<std::is_scalar<T>,
1742 std::is_same<T, detail::decay_t<U>>>::value &&
1743 std::is_constructible<T, U>::value &&
1744 std::is_assignable<G &, U>::value &&
1745 std::is_nothrow_move_constructible<E>::value)> * = nullptr>
1747 if (has_value()) {
1748 val() = std::forward<U>(v);
1749 } else {
1750 err().~unexpected<E>();
1751 ::new (valptr()) T(std::forward<U>(v));
1752 this->m_has_val = true;
1753 }
1754
1755 return *this;
1756 }
1757
1758 template <
1759 class U = T, class G = T,
1760 detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =
1761 nullptr,
1762 detail::enable_if_t<!std::is_void<U>::value> * = nullptr,
1763 detail::enable_if_t<
1764 (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
1765 !detail::conjunction<std::is_scalar<T>,
1766 std::is_same<T, detail::decay_t<U>>>::value &&
1767 std::is_constructible<T, U>::value &&
1768 std::is_assignable<G &, U>::value &&
1769 std::is_nothrow_move_constructible<E>::value)> * = nullptr>
1771 if (has_value()) {
1772 val() = std::forward<U>(v);
1773 } else {
1774 auto tmp = std::move(err());
1775 err().~unexpected<E>();
1776
1777#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
1778 try {
1779 ::new (valptr()) T(std::forward<U>(v));
1780 this->m_has_val = true;
1781 } catch (...) {
1782 err() = std::move(tmp);
1783 throw;
1784 }
1785#else
1786 ::new (valptr()) T(std::forward<U>(v));
1787 this->m_has_val = true;
1788#endif
1789 }
1790
1791 return *this;
1792 }
1793
1794 template <class G = E,
1795 detail::enable_if_t<std::is_nothrow_copy_constructible<G>::value &&
1796 std::is_assignable<G &, G>::value> * = nullptr>
1797 expected &operator=(const unexpected<G> &rhs) {
1798 if (!has_value()) {
1799 err() = rhs;
1800 } else {
1801 this->destroy_val();
1802 ::new (errptr()) unexpected<E>(rhs);
1803 this->m_has_val = false;
1804 }
1805
1806 return *this;
1807 }
1808
1809 template <class G = E,
1810 detail::enable_if_t<std::is_nothrow_move_constructible<G>::value &&
1811 std::is_move_assignable<G>::value> * = nullptr>
1812 expected &operator=(unexpected<G> &&rhs) noexcept {
1813 if (!has_value()) {
1814 err() = std::move(rhs);
1815 } else {
1816 this->destroy_val();
1817 ::new (errptr()) unexpected<E>(std::move(rhs));
1818 this->m_has_val = false;
1819 }
1820
1821 return *this;
1822 }
1823
1824 template <class... Args, detail::enable_if_t<std::is_nothrow_constructible<
1825 T, Args &&...>::value> * = nullptr>
1826 void emplace(Args &&...args) {
1827 if (has_value()) {
1828 val().~T();
1829 } else {
1830 err().~unexpected<E>();
1831 this->m_has_val = true;
1832 }
1833 ::new (valptr()) T(std::forward<Args>(args)...);
1834 }
1835
1836 template <class... Args, detail::enable_if_t<!std::is_nothrow_constructible<
1837 T, Args &&...>::value> * = nullptr>
1838 void emplace(Args &&...args) {
1839 if (has_value()) {
1840 val().~T();
1841 ::new (valptr()) T(std::forward<Args>(args)...);
1842 } else {
1843 auto tmp = std::move(err());
1844 err().~unexpected<E>();
1845
1846#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
1847 try {
1848 ::new (valptr()) T(std::forward<Args>(args)...);
1849 this->m_has_val = true;
1850 } catch (...) {
1851 err() = std::move(tmp);
1852 throw;
1853 }
1854#else
1855 ::new (valptr()) T(std::forward<Args>(args)...);
1856 this->m_has_val = true;
1857#endif
1858 }
1859 }
1860
1861 template <class U, class... Args,
1862 detail::enable_if_t<std::is_nothrow_constructible<
1863 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1864 void emplace(std::initializer_list<U> il, Args &&...args) {
1865 if (has_value()) {
1866 T t(il, std::forward<Args>(args)...);
1867 val() = std::move(t);
1868 } else {
1869 err().~unexpected<E>();
1870 ::new (valptr()) T(il, std::forward<Args>(args)...);
1871 this->m_has_val = true;
1872 }
1873 }
1874
1875 template <class U, class... Args,
1876 detail::enable_if_t<!std::is_nothrow_constructible<
1877 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1878 void emplace(std::initializer_list<U> il, Args &&...args) {
1879 if (has_value()) {
1880 T t(il, std::forward<Args>(args)...);
1881 val() = std::move(t);
1882 } else {
1883 auto tmp = std::move(err());
1884 err().~unexpected<E>();
1885
1886#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
1887 try {
1888 ::new (valptr()) T(il, std::forward<Args>(args)...);
1889 this->m_has_val = true;
1890 } catch (...) {
1891 err() = std::move(tmp);
1892 throw;
1893 }
1894#else
1895 ::new (valptr()) T(il, std::forward<Args>(args)...);
1896 this->m_has_val = true;
1897#endif
1898 }
1899 }
1900
1901private:
1902 using t_is_void = std::true_type;
1903 using t_is_not_void = std::false_type;
1908
1909 void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept {
1910 // swapping void is a no-op
1911 }
1912
1913 void swap_where_both_have_value(expected &rhs, t_is_not_void) {
1914 using std::swap;
1915 swap(val(), rhs.val());
1916 }
1917
1918 void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept(
1919 std::is_nothrow_move_constructible<E>::value) {
1920 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1921 rhs.err().~unexpected_type();
1922 std::swap(this->m_has_val, rhs.m_has_val);
1923 }
1924
1925 void swap_where_only_one_has_value(expected &rhs, t_is_not_void) {
1926 swap_where_only_one_has_value_and_t_is_not_void(
1927 rhs, typename std::is_nothrow_move_constructible<T>::type{},
1928 typename std::is_nothrow_move_constructible<E>::type{});
1929 }
1930
1931 void swap_where_only_one_has_value_and_t_is_not_void(
1932 expected &rhs, t_is_nothrow_move_constructible,
1933 e_is_nothrow_move_constructible) noexcept {
1934 auto temp = std::move(val());
1935 val().~T();
1936 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1937 rhs.err().~unexpected_type();
1938 ::new (rhs.valptr()) T(std::move(temp));
1939 std::swap(this->m_has_val, rhs.m_has_val);
1940 }
1941
1942 void swap_where_only_one_has_value_and_t_is_not_void(
1943 expected &rhs, t_is_nothrow_move_constructible,
1944 move_constructing_e_can_throw) {
1945 auto temp = std::move(val());
1946 val().~T();
1947#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
1948 try {
1949 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1950 rhs.err().~unexpected_type();
1951 ::new (rhs.valptr()) T(std::move(temp));
1952 std::swap(this->m_has_val, rhs.m_has_val);
1953 } catch (...) {
1954 val() = std::move(temp);
1955 throw;
1956 }
1957#else
1958 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1959 rhs.err().~unexpected_type();
1960 ::new (rhs.valptr()) T(std::move(temp));
1961 std::swap(this->m_has_val, rhs.m_has_val);
1962#endif
1963 }
1964
1965 void swap_where_only_one_has_value_and_t_is_not_void(
1966 expected &rhs, move_constructing_t_can_throw,
1967 e_is_nothrow_move_constructible) {
1968 auto temp = std::move(rhs.err());
1969 rhs.err().~unexpected_type();
1970#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
1971 try {
1972 ::new (rhs.valptr()) T(std::move(val()));
1973 val().~T();
1974 ::new (errptr()) unexpected_type(std::move(temp));
1975 std::swap(this->m_has_val, rhs.m_has_val);
1976 } catch (...) {
1977 rhs.err() = std::move(temp);
1978 throw;
1979 }
1980#else
1981 ::new (rhs.valptr()) T(std::move(val()));
1982 val().~T();
1983 ::new (errptr()) unexpected_type(std::move(temp));
1984 std::swap(this->m_has_val, rhs.m_has_val);
1985#endif
1986 }
1987
1988public:
1989 template <class OT = T, class OE = E>
1994 swap(expected &rhs) noexcept(
1999 if (has_value() && rhs.has_value()) {
2000 swap_where_both_have_value(rhs, typename std::is_void<T>::type{});
2001 } else if (!has_value() && rhs.has_value()) {
2002 rhs.swap(*this);
2003 } else if (has_value()) {
2004 swap_where_only_one_has_value(rhs, typename std::is_void<T>::type{});
2005 } else {
2006 using std::swap;
2007 swap(err(), rhs.err());
2008 }
2009 }
2010
2011 constexpr const T *operator->() const {
2013 return valptr();
2014 }
2017 return valptr();
2018 }
2019
2020 template <class U = T,
2021 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2022 constexpr const U &operator*() const & {
2024 return val();
2025 }
2026 template <class U = T,
2027 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2030 return val();
2031 }
2032 template <class U = T,
2033 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2034 constexpr const U &&operator*() const && {
2036 return std::move(val());
2037 }
2038 template <class U = T,
2039 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2042 return std::move(val());
2043 }
2044
2045 constexpr bool has_value() const noexcept { return this->m_has_val; }
2046 constexpr explicit operator bool() const noexcept { return this->m_has_val; }
2047
2048 template <class U = T,
2049 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2051 if (!has_value())
2052 detail::throw_exception(bad_expected_access<E>(err().error()));
2053 return val();
2054 }
2055 template <class U = T,
2056 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2058 if (!has_value())
2059 detail::throw_exception(bad_expected_access<E>(err().error()));
2060 return val();
2061 }
2062 template <class U = T,
2063 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2065 if (!has_value())
2066 detail::throw_exception(bad_expected_access<E>(std::move(err()).error()));
2067 return std::move(val());
2068 }
2069 template <class U = T,
2070 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2072 if (!has_value())
2073 detail::throw_exception(bad_expected_access<E>(std::move(err()).error()));
2074 return std::move(val());
2075 }
2076
2077 constexpr const E &error() const & {
2079 return err().error();
2080 }
2083 return err().error();
2084 }
2085 constexpr const E &&error() const && {
2087 return std::move(err().error());
2088 }
2091 return std::move(err().error());
2092 }
2093
2094 template <class U> constexpr T value_or(U &&v) const & {
2095 static_assert(std::is_copy_constructible<T>::value &&
2096 std::is_convertible<U &&, T>::value,
2097 "T must be copy-constructible and convertible to from U&&");
2098 return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
2099 }
2100 template <class U> Q23_TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && {
2101 static_assert(std::is_move_constructible<T>::value &&
2102 std::is_convertible<U &&, T>::value,
2103 "T must be move-constructible and convertible to from U&&");
2104 return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
2105 }
2106};
2107
2108namespace detail {
2109template <class Exp> using exp_t = typename detail::decay_t<Exp>::value_type;
2110template <class Exp> using err_t = typename detail::decay_t<Exp>::error_type;
2111template <class Exp, class Ret> using ret_t = expected<Ret, err_t<Exp>>;
2112
2113#ifdef Q23_TL_EXPECTED_CXX14
2114template <class Exp, class F,
2115 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2116 class Ret = decltype(detail::invoke(std::declval<F>(),
2117 *std::declval<Exp>()))>
2118constexpr auto and_then_impl(Exp &&exp, F &&f) {
2119 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2120
2121 return exp.has_value()
2122 ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
2123 : Ret(unexpect, std::forward<Exp>(exp).error());
2124}
2125
2126template <class Exp, class F,
2127 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2128 class Ret = decltype(detail::invoke(std::declval<F>()))>
2129constexpr auto and_then_impl(Exp &&exp, F &&f) {
2130 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2131
2132 return exp.has_value() ? detail::invoke(std::forward<F>(f))
2133 : Ret(unexpect, std::forward<Exp>(exp).error());
2134}
2135#else
2136template <class> struct TC;
2137template <class Exp, class F,
2138 class Ret = decltype(detail::invoke(std::declval<F>(),
2139 *std::declval<Exp>())),
2140 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr>
2141auto and_then_impl(Exp &&exp, F &&f) -> Ret {
2142 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2143
2144 return exp.has_value()
2145 ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
2146 : Ret(unexpect, std::forward<Exp>(exp).error());
2147}
2148
2149template <class Exp, class F,
2150 class Ret = decltype(detail::invoke(std::declval<F>())),
2151 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr>
2152constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
2153 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2154
2155 return exp.has_value() ? detail::invoke(std::forward<F>(f))
2156 : Ret(unexpect, std::forward<Exp>(exp).error());
2157}
2158#endif
2159
2160#ifdef Q23_TL_EXPECTED_CXX14
2161template <class Exp, class F,
2162 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2163 class Ret = decltype(detail::invoke(std::declval<F>(),
2164 *std::declval<Exp>())),
2165 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2166constexpr auto expected_map_impl(Exp &&exp, F &&f) {
2167 using result = ret_t<Exp, detail::decay_t<Ret>>;
2168 return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
2169 *std::forward<Exp>(exp)))
2170 : result(unexpect, std::forward<Exp>(exp).error());
2171}
2172
2173template <class Exp, class F,
2174 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2175 class Ret = decltype(detail::invoke(std::declval<F>(),
2176 *std::declval<Exp>())),
2177 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2178auto expected_map_impl(Exp &&exp, F &&f) {
2179 using result = expected<void, err_t<Exp>>;
2180 if (exp.has_value()) {
2181 detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
2182 return result();
2183 }
2184
2185 return result(unexpect, std::forward<Exp>(exp).error());
2186}
2187
2188template <class Exp, class F,
2189 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2190 class Ret = decltype(detail::invoke(std::declval<F>())),
2191 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2192constexpr auto expected_map_impl(Exp &&exp, F &&f) {
2193 using result = ret_t<Exp, detail::decay_t<Ret>>;
2194 return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
2195 : result(unexpect, std::forward<Exp>(exp).error());
2196}
2197
2198template <class Exp, class F,
2199 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2200 class Ret = decltype(detail::invoke(std::declval<F>())),
2201 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2202auto expected_map_impl(Exp &&exp, F &&f) {
2203 using result = expected<void, err_t<Exp>>;
2204 if (exp.has_value()) {
2205 detail::invoke(std::forward<F>(f));
2206 return result();
2207 }
2208
2209 return result(unexpect, std::forward<Exp>(exp).error());
2210}
2211#else
2212template <class Exp, class F,
2213 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2214 class Ret = decltype(detail::invoke(std::declval<F>(),
2215 *std::declval<Exp>())),
2216 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2217
2218constexpr auto expected_map_impl(Exp &&exp, F &&f)
2219 -> ret_t<Exp, detail::decay_t<Ret>> {
2220 using result = ret_t<Exp, detail::decay_t<Ret>>;
2221
2222 return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
2223 *std::forward<Exp>(exp)))
2225}
2226
2227template <class Exp, class F,
2228 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2229 class Ret = decltype(detail::invoke(std::declval<F>(),
2230 *std::declval<Exp>())),
2231 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2232
2233auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
2234 if (exp.has_value()) {
2236 return {};
2237 }
2238
2239 return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
2240}
2241
2242template <class Exp, class F,
2243 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2244 class Ret = decltype(detail::invoke(std::declval<F>())),
2245 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2246
2247constexpr auto expected_map_impl(Exp &&exp, F &&f)
2248 -> ret_t<Exp, detail::decay_t<Ret>> {
2249 using result = ret_t<Exp, detail::decay_t<Ret>>;
2250
2251 return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
2253}
2254
2255template <class Exp, class F,
2256 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2257 class Ret = decltype(detail::invoke(std::declval<F>())),
2258 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2259
2260auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
2261 if (exp.has_value()) {
2262 detail::invoke(std::forward<F>(f));
2263 return {};
2264 }
2265
2266 return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
2267}
2268#endif
2269
2270#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) &&
2271 !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
2272template <class Exp, class F,
2273 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2274 class Ret = decltype(detail::invoke(std::declval<F>(),
2275 std::declval<Exp>().error())),
2276 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2277constexpr auto map_error_impl(Exp &&exp, F &&f) {
2278 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2279 return exp.has_value()
2280 ? result(*std::forward<Exp>(exp))
2281 : result(unexpect, detail::invoke(std::forward<F>(f),
2282 std::forward<Exp>(exp).error()));
2283}
2284template <class Exp, class F,
2285 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2286 class Ret = decltype(detail::invoke(std::declval<F>(),
2287 std::declval<Exp>().error())),
2288 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2289auto map_error_impl(Exp &&exp, F &&f) {
2290 using result = expected<exp_t<Exp>, monostate>;
2291 if (exp.has_value()) {
2292 return result(*std::forward<Exp>(exp));
2293 }
2294
2295 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2296 return result(unexpect, monostate{});
2297}
2298template <class Exp, class F,
2299 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2300 class Ret = decltype(detail::invoke(std::declval<F>(),
2301 std::declval<Exp>().error())),
2302 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2303constexpr auto map_error_impl(Exp &&exp, F &&f) {
2304 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2305 return exp.has_value()
2306 ? result()
2307 : result(unexpect, detail::invoke(std::forward<F>(f),
2308 std::forward<Exp>(exp).error()));
2309}
2310template <class Exp, class F,
2311 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2312 class Ret = decltype(detail::invoke(std::declval<F>(),
2313 std::declval<Exp>().error())),
2314 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2315auto map_error_impl(Exp &&exp, F &&f) {
2316 using result = expected<exp_t<Exp>, monostate>;
2317 if (exp.has_value()) {
2318 return result();
2319 }
2320
2321 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2322 return result(unexpect, monostate{});
2323}
2324#else
2325template <class Exp, class F,
2326 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2327 class Ret = decltype(detail::invoke(std::declval<F>(),
2328 std::declval<Exp>().error())),
2329 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2330constexpr auto map_error_impl(Exp &&exp, F &&f)
2332 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2333
2334 return exp.has_value()
2335 ? result(*std::forward<Exp>(exp))
2337 std::forward<Exp>(exp).error()));
2338}
2339
2340template <class Exp, class F,
2341 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2342 class Ret = decltype(detail::invoke(std::declval<F>(),
2343 std::declval<Exp>().error())),
2344 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2346 using result = expected<exp_t<Exp>, monostate>;
2347 if (exp.has_value()) {
2348 return result(*std::forward<Exp>(exp));
2349 }
2350
2352 return result(unexpect, monostate{});
2353}
2354
2355template <class Exp, class F,
2356 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2357 class Ret = decltype(detail::invoke(std::declval<F>(),
2358 std::declval<Exp>().error())),
2359 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2360constexpr auto map_error_impl(Exp &&exp, F &&f)
2362 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2363
2364 return exp.has_value()
2365 ? result()
2367 std::forward<Exp>(exp).error()));
2368}
2369
2370template <class Exp, class F,
2371 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2372 class Ret = decltype(detail::invoke(std::declval<F>(),
2373 std::declval<Exp>().error())),
2374 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2376 using result = expected<exp_t<Exp>, monostate>;
2377 if (exp.has_value()) {
2378 return result();
2379 }
2380
2382 return result(unexpect, monostate{});
2383}
2384#endif
2385
2386#ifdef Q23_TL_EXPECTED_CXX14
2387template <class Exp, class F,
2388 class Ret = decltype(detail::invoke(std::declval<F>(),
2389 std::declval<Exp>().error())),
2390 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2391constexpr auto or_else_impl(Exp &&exp, F &&f) {
2392 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2393 return exp.has_value() ? std::forward<Exp>(exp)
2394 : detail::invoke(std::forward<F>(f),
2395 std::forward<Exp>(exp).error());
2396}
2397
2398template <class Exp, class F,
2399 class Ret = decltype(detail::invoke(std::declval<F>(),
2400 std::declval<Exp>().error())),
2401 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2402detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
2403 return exp.has_value() ? std::forward<Exp>(exp)
2404 : (detail::invoke(std::forward<F>(f),
2405 std::forward<Exp>(exp).error()),
2406 std::forward<Exp>(exp));
2407}
2408#else
2409template <class Exp, class F,
2410 class Ret = decltype(detail::invoke(std::declval<F>(),
2411 std::declval<Exp>().error())),
2412 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2413auto or_else_impl(Exp &&exp, F &&f) -> Ret {
2414 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2415 return exp.has_value() ? std::forward<Exp>(exp)
2416 : detail::invoke(std::forward<F>(f),
2417 std::forward<Exp>(exp).error());
2418}
2419
2420template <class Exp, class F,
2421 class Ret = decltype(detail::invoke(std::declval<F>(),
2422 std::declval<Exp>().error())),
2423 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2425 return exp.has_value() ? std::forward<Exp>(exp)
2426 : (detail::invoke(std::forward<F>(f),
2427 std::forward<Exp>(exp).error()),
2428 std::forward<Exp>(exp));
2429}
2430#endif
2431} // namespace detail
2432
2433template <class T, class E, class U, class F>
2434constexpr bool operator==(const expected<T, E> &lhs,
2435 const expected<U, F> &rhs) {
2436 return (lhs.has_value() != rhs.has_value())
2437 ? false
2438 : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
2439}
2440template <class T, class E, class U, class F>
2441constexpr bool operator!=(const expected<T, E> &lhs,
2442 const expected<U, F> &rhs) {
2443 return (lhs.has_value() != rhs.has_value())
2444 ? true
2445 : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs);
2446}
2447template <class E, class F>
2448constexpr bool operator==(const expected<void, E> &lhs,
2449 const expected<void, F> &rhs) {
2450 return (lhs.has_value() != rhs.has_value())
2451 ? false
2452 : (!lhs.has_value() ? lhs.error() == rhs.error() : true);
2453}
2454template <class E, class F>
2455constexpr bool operator!=(const expected<void, E> &lhs,
2456 const expected<void, F> &rhs) {
2457 return (lhs.has_value() != rhs.has_value())
2458 ? true
2459 : (!lhs.has_value() ? lhs.error() != rhs.error() : false);
2460}
2461
2462template <class T, class E, class U>
2463constexpr bool operator==(const expected<T, E> &x, const U &v) {
2464 return x.has_value() ? *x == v : false;
2465}
2466template <class T, class E, class U>
2467constexpr bool operator==(const U &v, const expected<T, E> &x) {
2468 return x.has_value() ? *x == v : false;
2469}
2470template <class T, class E, class U>
2471constexpr bool operator!=(const expected<T, E> &x, const U &v) {
2472 return x.has_value() ? *x != v : true;
2473}
2474template <class T, class E, class U>
2475constexpr bool operator!=(const U &v, const expected<T, E> &x) {
2476 return x.has_value() ? *x != v : true;
2477}
2478
2479template <class T, class E>
2480constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) {
2481 return x.has_value() ? false : x.error() == e.error();
2482}
2483template <class T, class E>
2484constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) {
2485 return x.has_value() ? false : x.error() == e.error();
2486}
2487template <class T, class E>
2488constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) {
2489 return x.has_value() ? true : x.error() != e.error();
2490}
2491template <class T, class E>
2492constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
2493 return x.has_value() ? true : x.error() != e.error();
2494}
2495
2496template <class T, class E,
2497 detail::enable_if_t<(std::is_void<T>::value ||
2498 std::is_move_constructible<T>::value) &&
2499 detail::is_swappable<T>::value &&
2500 std::is_move_constructible<E>::value &&
2501 detail::is_swappable<E>::value> * = nullptr>
2502void swap(expected<T, E> &lhs,
2503 expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
2504 lhs.swap(rhs);
2505}
2506} // namespace q23
2507QT_END_NAMESPACE
2508
2509#endif
const E && error() const &&
virtual const char * what() const noexcept override
const E & error() const &
constexpr T value_or(U &&v) const &
constexpr const E && error() const &&
expected constexpr or_else(F &&f) const &&
constexpr expected(unexpect_t, Args &&...args)
expected Q23_TL_EXPECTED_11_CONSTEXPR or_else(F &&f) &
constexpr expected(in_place_t, std::initializer_list< U > il, Args &&...args)
constexpr const U & operator*() const &
Q23_TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) &&
expected & operator=(const unexpected< G > &rhs)
Q23_TL_EXPECTED_11_CONSTEXPR const U & value() const &
expected Q23_TL_EXPECTED_11_CONSTEXPR or_else(F &&f) &&
constexpr expected(const expected &rhs)=default
Q23_TL_EXPECTED_11_CONSTEXPR expected(expected< U, G > &&rhs)
unexpected< E > unexpected_type
Q23_TL_EXPECTED_11_CONSTEXPR E && error() &&
Q23_TL_EXPECTED_11_CONSTEXPR U && value() &&
expected & operator=(expected &&rhs)=default
Q23_TL_EXPECTED_11_CONSTEXPR const U && value() const &&
Q23_TL_EXPECTED_11_CONSTEXPR expected(const expected< U, G > &rhs)
detail::enable_if_t< detail::is_swappable< OT >::value &&detail::is_swappable< OE >::value &&(std::is_nothrow_move_constructible< OT >::value||std::is_nothrow_move_constructible< OE >::value)> swap(expected &rhs) noexcept(std::is_nothrow_move_constructible< T >::value &&detail::is_nothrow_swappable< T >::value &&std::is_nothrow_move_constructible< E >::value &&detail::is_nothrow_swappable< E >::value)
Q23_TL_EXPECTED_11_CONSTEXPR U & operator*() &
void emplace(std::initializer_list< U > il, Args &&...args)
constexpr expected(unexpect_t, std::initializer_list< U > il, Args &&...args)
expected constexpr or_else(F &&f) const &
Q23_TL_EXPECTED_11_CONSTEXPR U && operator*() &&
constexpr bool has_value() const noexcept
constexpr expected()=default
constexpr expected(in_place_t, Args &&...args)
void emplace(Args &&...args)
Q23_TL_EXPECTED_11_CONSTEXPR E & error() &
constexpr const E & error() const &
constexpr expected(unexpected< G > &&e) noexcept(std::is_nothrow_constructible< E, G && >::value)
constexpr const T * operator->() const
expected & operator=(unexpected< G > &&rhs) noexcept
constexpr expected(const unexpected< G > &e)
constexpr const U && operator*() const &&
Q23_TL_EXPECTED_11_CONSTEXPR T * operator->()
expected & operator=(U &&v)
expected & operator=(const expected &rhs)=default
constexpr operator bool() const noexcept
constexpr expected(expected &&rhs)=default
Q23_TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
Q23_TL_EXPECTED_11_CONSTEXPR U & value() &
constexpr unexpected(in_place_t, Args &&...args)
constexpr unexpected(const E &e)
constexpr const E & error() const &
Q23_TL_EXPECTED_11_CONSTEXPR E && error() &&
unexpected()=delete
Q23_TL_EXPECTED_11_CONSTEXPR E & error() &
constexpr unexpected(in_place_t, std::initializer_list< U > l, Args &&...args)
constexpr const E && error() const &&
constexpr unexpected(E &&e)
std::is_same< decltype(swap(std::declval< T & >(), std::declval< U & >())), tag > uses_std(int)
std::false_type can_swap(...) noexcept(false)
tag swap(T(&a)[N], T(&b)[N])
std::true_type can_swap(int) noexcept(noexcept(swap(std::declval< T & >(), std::declval< U & >())))
std::false_type uses_std(...)
constexpr auto invoke(Fn &&f, Args &&...args) noexcept(noexcept(std::forward< Fn >(f)(std::forward< Args >(args)...))) -> decltype(std::forward< Fn >(f)(std::forward< Args >(args)...))
typename std::conditional< B, T, F >::type conditional_t
invoke_result_impl< F, void, Us... > invoke_result
typename std::remove_reference< T >::type remove_reference_t
typename std::enable_if< E, T >::type enable_if_t
static constexpr no_init_t no_init
typename std::decay< T >::type decay_t
Q23_TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e)
typename std::remove_const< T >::type remove_const_t
constexpr auto invoke(Fn &&f, Args &&...args) noexcept(noexcept(std::mem_fn(f)(std::forward< Args >(args)...))) -> decltype(std::mem_fn(f)(std::forward< Args >(args)...))
constexpr bool operator!=(const unexpected< E > &e, const expected< T, E > &x)
constexpr bool operator!=(const unexpected< E > &lhs, const unexpected< E > &rhs)
constexpr bool operator<(const unexpected< E > &lhs, const unexpected< E > &rhs)
constexpr bool operator>(const unexpected< E > &lhs, const unexpected< E > &rhs)
constexpr bool operator==(const unexpected< E > &lhs, const unexpected< E > &rhs)
constexpr bool operator==(const expected< void, E > &lhs, const expected< void, F > &rhs)
constexpr bool operator!=(const expected< T, E > &lhs, const expected< U, F > &rhs)
unexpected< typename std::decay< E >::type > make_unexpected(E &&e)
constexpr bool operator<=(const unexpected< E > &lhs, const unexpected< E > &rhs)
void swap(expected< T, E > &lhs, expected< T, E > &rhs) noexcept(noexcept(lhs.swap(rhs)))
constexpr bool operator!=(const expected< T, E > &x, const U &v)
constexpr bool operator==(const unexpected< E > &e, const expected< T, E > &x)
constexpr bool operator==(const expected< T, E > &x, const U &v)
constexpr bool operator==(const U &v, const expected< T, E > &x)
static constexpr unexpect_t unexpect
constexpr bool operator!=(const expected< T, E > &x, const unexpected< E > &e)
static constexpr in_place_t in_place
constexpr bool operator>=(const unexpected< E > &lhs, const unexpected< E > &rhs)
constexpr bool operator!=(const expected< void, E > &lhs, const expected< void, F > &rhs)
constexpr bool operator==(const expected< T, E > &x, const unexpected< E > &e)
constexpr bool operator==(const expected< T, E > &lhs, const expected< U, F > &rhs)
constexpr bool operator!=(const U &v, const expected< T, E > &x)
#define Q23_TL_ASSERT
Definition qexpected_p.h:48
#define Q23_TL_EXPECTED_11_CONSTEXPR
#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)
#define Q23_TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)
#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T)
#define Q23_TL_EXPECTED_MSVC2015_CONSTEXPR
Definition qexpected_p.h:62
#define Q23_TL_CPLUSPLUS
constexpr default_constructor_tag()=default
expected_copy_assign_base(expected_copy_assign_base &&rhs)=default
expected_copy_assign_base(const expected_copy_assign_base &rhs)=default
expected_copy_assign_base & operator=(const expected_copy_assign_base &rhs)
expected_copy_assign_base & operator=(expected_copy_assign_base &&rhs)=default
expected_copy_base & operator=(const expected_copy_base &rhs)=default
expected_copy_base(const expected_copy_base &rhs)
expected_copy_base(expected_copy_base &&rhs)=default
expected_copy_base & operator=(expected_copy_base &&rhs)=default
constexpr expected_default_ctor_base(expected_default_ctor_base const &) noexcept=default
constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept=default
constexpr expected_default_ctor_base(default_constructor_tag)
expected_default_ctor_base & operator=(expected_default_ctor_base const &) noexcept=default
expected_default_ctor_base & operator=(expected_default_ctor_base &&) noexcept=default
expected_default_ctor_base & operator=(expected_default_ctor_base &&) noexcept=default
constexpr expected_default_ctor_base(expected_default_ctor_base const &) noexcept=default
expected_default_ctor_base & operator=(expected_default_ctor_base const &) noexcept=default
constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept=default
constexpr expected_default_ctor_base(default_constructor_tag)
constexpr expected_default_ctor_base() noexcept=default
expected_delete_assign_base(expected_delete_assign_base &&) noexcept=default
expected_delete_assign_base(const expected_delete_assign_base &)=default
expected_delete_assign_base & operator=(expected_delete_assign_base &&) noexcept=delete
expected_delete_assign_base & operator=(const expected_delete_assign_base &)=delete
expected_delete_assign_base(expected_delete_assign_base &&) noexcept=default
expected_delete_assign_base & operator=(expected_delete_assign_base &&) noexcept=default
expected_delete_assign_base & operator=(const expected_delete_assign_base &)=delete
expected_delete_assign_base(const expected_delete_assign_base &)=default
expected_delete_assign_base(expected_delete_assign_base &&) noexcept=default
expected_delete_assign_base & operator=(const expected_delete_assign_base &)=default
expected_delete_assign_base(const expected_delete_assign_base &)=default
expected_delete_assign_base & operator=(expected_delete_assign_base &&) noexcept=delete
expected_delete_assign_base(expected_delete_assign_base &&) noexcept=default
expected_delete_assign_base & operator=(const expected_delete_assign_base &)=default
expected_delete_assign_base & operator=(expected_delete_assign_base &&) noexcept=default
expected_delete_assign_base(const expected_delete_assign_base &)=default
expected_delete_ctor_base & operator=(expected_delete_ctor_base &&) noexcept=default
expected_delete_ctor_base & operator=(const expected_delete_ctor_base &)=default
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept=delete
expected_delete_ctor_base(const expected_delete_ctor_base &)=delete
expected_delete_ctor_base(const expected_delete_ctor_base &)=delete
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept=default
expected_delete_ctor_base & operator=(const expected_delete_ctor_base &)=default
expected_delete_ctor_base & operator=(expected_delete_ctor_base &&) noexcept=default
expected_delete_ctor_base(const expected_delete_ctor_base &)=default
expected_delete_ctor_base & operator=(expected_delete_ctor_base &&) noexcept=default
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept=delete
expected_delete_ctor_base & operator=(const expected_delete_ctor_base &)=default
expected_delete_ctor_base & operator=(expected_delete_ctor_base &&) noexcept=default
expected_delete_ctor_base & operator=(const expected_delete_ctor_base &)=default
expected_delete_ctor_base(const expected_delete_ctor_base &)=default
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept=default
expected_move_assign_base & operator=(const expected_move_assign_base &rhs)=default
expected_move_assign_base & operator=(expected_move_assign_base &&rhs) noexcept(std::is_nothrow_move_constructible< T >::value &&std::is_nothrow_move_assignable< T >::value)
expected_move_assign_base(const expected_move_assign_base &rhs)=default
expected_move_assign_base(expected_move_assign_base &&rhs)=default
expected_move_base(expected_move_base &&rhs) noexcept(std::is_nothrow_move_constructible< T >::value)
expected_move_base(const expected_move_base &rhs)=default
expected_move_base & operator=(const expected_move_base &rhs)=default
expected_move_base & operator=(expected_move_base &&rhs)=default
constexpr const unexpected< E > && geterr() const &&
Q23_TL_EXPECTED_11_CONSTEXPR unexpected< E > && geterr() &&
void construct_error(Args &&...args) noexcept
Q23_TL_EXPECTED_11_CONSTEXPR unexpected< E > & geterr() &
constexpr const unexpected< E > & geterr() const &
Q23_TL_EXPECTED_11_CONSTEXPR void destroy_val()
constexpr const unexpected< E > && geterr() const &&
Q23_TL_EXPECTED_11_CONSTEXPR unexpected< E > & geterr() &
void construct(Args &&...args) noexcept
constexpr const unexpected< E > & geterr() const &
void construct_with(Rhs &&rhs) noexcept
Q23_TL_EXPECTED_11_CONSTEXPR unexpected< E > && geterr() &&
constexpr const T && get() const &&
constexpr const T & get() const &
Q23_TL_EXPECTED_11_CONSTEXPR T & get() &
void construct_error(Args &&...args) noexcept
Q23_TL_EXPECTED_11_CONSTEXPR T && get() &&
Q23_TL_EXPECTED_11_CONSTEXPR void destroy_val()
expected_storage_base(expected_storage_base &&)=default
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
constexpr expected_storage_base(in_place_t, Args &&...args)
constexpr expected_storage_base(in_place_t, std::initializer_list< U > il, Args &&...args)
expected_storage_base & operator=(const expected_storage_base &)=default
expected_storage_base & operator=(expected_storage_base &&)=default
expected_storage_base(const expected_storage_base &)=default
constexpr expected_storage_base(unexpect_t, Args &&...args)
expected_storage_base & operator=(const expected_storage_base &)=default
expected_storage_base(const expected_storage_base &)=default
constexpr expected_storage_base(unexpect_t, Args &&...args)
expected_storage_base(expected_storage_base &&)=default
Q23_TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
constexpr expected_storage_base(in_place_t, std::initializer_list< U > il, Args &&...args)
constexpr expected_storage_base(in_place_t, Args &&...args)
expected_storage_base & operator=(expected_storage_base &&)=default
expected_storage_base(expected_storage_base &&)=default
expected_storage_base & operator=(const expected_storage_base &)=default
constexpr expected_storage_base(in_place_t, std::initializer_list< U > il, Args &&...args)
constexpr expected_storage_base(unexpect_t, Args &&...args)
expected_storage_base(const expected_storage_base &)=default
expected_storage_base & operator=(expected_storage_base &&)=default
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
constexpr expected_storage_base(in_place_t, Args &&...args)
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
expected_storage_base & operator=(expected_storage_base &&)=default
expected_storage_base(expected_storage_base &&)=default
expected_storage_base & operator=(const expected_storage_base &)=default
constexpr expected_storage_base(unexpect_t, Args &&...args)
expected_storage_base(const expected_storage_base &)=default
expected_storage_base(expected_storage_base &&)=default
expected_storage_base & operator=(expected_storage_base &&)=default
expected_storage_base(const expected_storage_base &)=default
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
expected_storage_base & operator=(const expected_storage_base &)=default
constexpr expected_storage_base(unexpect_t, Args &&...args)
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
constexpr expected_storage_base(in_place_t, std::initializer_list< U > il, Args &&...args)
constexpr expected_storage_base(no_init_t)
constexpr expected_storage_base(in_place_t, Args &&...args)
constexpr expected_storage_base(unexpect_t, Args &&...args)
in_place_t()=default
unexpect_t()=default