proxsuite 0.6.7
The Advanced Proximal Optimization Toolbox
Loading...
Searching...
No Matches
tl-optional.hpp
Go to the documentation of this file.
1
3// optional - An implementation of std::optional with extensions
4// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
5//
6// Documentation available at https://tl.tartanllama.xyz/
7//
8// To the extent possible under law, the author(s) have dedicated all
9// copyright and related and neighboring rights to this software to the
10// public domain worldwide. This software is distributed without any warranty.
11//
12// You should have received a copy of the CC0 Public Domain Dedication
13// along with this software. If not, see
14// <http://creativecommons.org/publicdomain/zero/1.0/>.
16
17#ifndef TL_OPTIONAL_HPP
18#define TL_OPTIONAL_HPP
19
20#define TL_OPTIONAL_VERSION_MAJOR 1
21#define TL_OPTIONAL_VERSION_MINOR 1
22#define TL_OPTIONAL_VERSION_PATCH 0
23
24#include <new>
25#include <exception>
26#include <functional>
27#include <type_traits>
28#include <utility>
29
30#if (defined(_MSC_VER) && _MSC_VER == 1900)
31#define TL_OPTIONAL_MSVC2015
32#endif
33
34#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
35 !defined(__clang__))
36#define TL_OPTIONAL_GCC49
37#endif
38
39#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
40 !defined(__clang__))
41#define TL_OPTIONAL_GCC54
42#endif
43
44#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \
45 !defined(__clang__))
46#define TL_OPTIONAL_GCC55
47#endif
48
49#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
50 !defined(__clang__))
51// GCC < 5 doesn't support overloading on const&& for member functions
52#define TL_OPTIONAL_NO_CONSTRR
53
54// GCC < 5 doesn't support some standard C++11 type traits
55#define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
56 std::has_trivial_copy_constructor<T>::value
57#define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
58 std::has_trivial_copy_assign<T>::value
59
60// This one will be different for GCC 5.7 if it's ever supported
61#define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) \
62 std::is_trivially_destructible<T>::value
63
64// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks
65// std::vector for non-copyable types
66#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
67#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
68#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
69namespace tl {
70namespace detail {
71template<class T>
72struct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T>
73{};
74#ifdef _GLIBCXX_VECTOR
75template<class T, class A>
76struct is_trivially_copy_constructible<std::vector<T, A>>
77 : std::is_trivially_copy_constructible<T>
78{};
79#endif
80}
81}
82#endif
83
84#define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
85 tl::detail::is_trivially_copy_constructible<T>::value
86#define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
87 std::is_trivially_copy_assignable<T>::value
88#define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) \
89 std::is_trivially_destructible<T>::value
90#else
91#define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
92 std::is_trivially_copy_constructible<T>::value
93#define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
94 std::is_trivially_copy_assignable<T>::value
95#define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) \
96 std::is_trivially_destructible<T>::value
97#endif
98
99#if __cplusplus > 201103L
100#define TL_OPTIONAL_CXX14
101#endif
102
103// constexpr implies const in C++11, not C++14
104#if (__cplusplus == 201103L || defined(TL_OPTIONAL_MSVC2015) || \
105 defined(TL_OPTIONAL_GCC49))
106#define TL_OPTIONAL_11_CONSTEXPR
107#else
108#define TL_OPTIONAL_11_CONSTEXPR constexpr
109#endif
110
111namespace tl {
112#ifndef TL_MONOSTATE_INPLACE_MUTEX
113#define TL_MONOSTATE_INPLACE_MUTEX
116{};
117
120{
121 explicit in_place_t() = default;
122};
124static constexpr in_place_t in_place{};
125#endif
126
127template<class T>
128class optional;
129
130namespace detail {
131#ifndef TL_TRAITS_MUTEX
132#define TL_TRAITS_MUTEX
133// C++14-style aliases for brevity
134template<class T>
135using remove_const_t = typename std::remove_const<T>::type;
136template<class T>
137using remove_reference_t = typename std::remove_reference<T>::type;
138template<class T>
139using decay_t = typename std::decay<T>::type;
140template<bool E, class T = void>
141using enable_if_t = typename std::enable_if<E, T>::type;
142template<bool B, class T, class F>
143using conditional_t = typename std::conditional<B, T, F>::type;
144
145// std::conjunction from C++17
146template<class...>
147struct conjunction : std::true_type
148{};
149template<class B>
151{};
152template<class B, class... Bs>
153struct conjunction<B, Bs...>
154 : std::conditional<bool(B::value), conjunction<Bs...>, B>::type
155{};
156
157#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
158#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
159#endif
160
161// In C++11 mode, there's an issue in libc++'s std::mem_fn
162// which results in a hard-error when using it in a noexcept expression
163// in some cases. This is a check to workaround the common failing case.
164#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
165template<class T>
166struct is_pointer_to_non_const_member_func : std::false_type
167{};
168template<class T, class Ret, class... Args>
169struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)> : std::true_type
170{};
171template<class T, class Ret, class... Args>
172struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)&>
173 : std::true_type
174{};
175template<class T, class Ret, class... Args>
176struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&>
177 : std::true_type
178{};
179template<class T, class Ret, class... Args>
180struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile>
181 : std::true_type
182{};
183template<class T, class Ret, class... Args>
184struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile&>
185 : std::true_type
186{};
187template<class T, class Ret, class... Args>
188struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile&&>
189 : std::true_type
190{};
191
192template<class T>
193struct is_const_or_const_ref : std::false_type
194{};
195template<class T>
196struct is_const_or_const_ref<T const&> : std::true_type
197{};
198template<class T>
199struct is_const_or_const_ref<T const> : std::true_type
200{};
201#endif
202
203// std::invoke from C++17
204// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
205template<
206 typename Fn,
207 typename... Args,
208#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
209 typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value &&
210 is_const_or_const_ref<Args...>::value)>,
211#endif
212 typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>,
213 int = 0>
214constexpr auto
215invoke(Fn&& f, Args&&... args) noexcept(
216 noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
217 -> decltype(std::mem_fn(f)(std::forward<Args>(args)...))
218{
219 return std::mem_fn(f)(std::forward<Args>(args)...);
220}
221
222template<typename Fn,
223 typename... Args,
224 typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>
225constexpr auto
226invoke(Fn&& f, Args&&... args) noexcept(
227 noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
228 -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...))
229{
230 return std::forward<Fn>(f)(std::forward<Args>(args)...);
231}
232
233// std::invoke_result from C++17
234template<class F, class, class... Us>
236
237template<class F, class... Us>
239 F,
240 decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
241 Us...>
242{
243 using type =
244 decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
245};
246
247template<class F, class... Us>
248using invoke_result = invoke_result_impl<F, void, Us...>;
249
250template<class F, class... Us>
251using invoke_result_t = typename invoke_result<F, Us...>::type;
252
253#if defined(_MSC_VER) && _MSC_VER <= 1900
254// TODO make a version which works with MSVC 2015
255template<class T, class U = T>
256struct is_swappable : std::true_type
257{};
258
259template<class T, class U = T>
260struct is_nothrow_swappable : std::true_type
261{};
262#else
263// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
264namespace swap_adl_tests {
265// if swap ADL finds this then it would call std::swap otherwise (same
266// signature)
267struct tag
268{};
269
270template<class T>
271tag
272swap(T&, T&);
273template<class T, std::size_t N>
274tag swap(T (&a)[N], T (&b)[N]);
275
276// helper functions to test if an unqualified swap is possible, and if it
277// becomes std::swap
278template<class, class>
279std::false_type
280can_swap(...) noexcept(false);
281template<class T,
282 class U,
283 class = decltype(swap(std::declval<T&>(), std::declval<U&>()))>
284std::true_type
285can_swap(int) noexcept(noexcept(swap(std::declval<T&>(), std::declval<U&>())));
286
287template<class, class>
288std::false_type
290template<class T, class U>
291std::is_same<decltype(swap(std::declval<T&>(), std::declval<U&>())), tag>
293
294template<class T>
296 : std::integral_constant<bool,
297 std::is_nothrow_move_constructible<T>::value &&
298 std::is_nothrow_move_assignable<T>::value>
299{};
300
301template<class T, std::size_t N>
304
305template<class T, class U>
307 : std::integral_constant<bool, noexcept(can_swap<T, U>(0))>
308{};
309} // namespace swap_adl_tests
310
311template<class T, class U = T>
313 : std::integral_constant<
314 bool,
315 decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
316 (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
317 (std::is_move_assignable<T>::value &&
318 std::is_move_constructible<T>::value))>
319{};
320
321template<class T, std::size_t N>
322struct is_swappable<T[N], T[N]>
323 : std::integral_constant<
324 bool,
325 decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
326 (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value ||
327 is_swappable<T, T>::value)>
328{};
329
330template<class T, class U = T>
332 : std::integral_constant<
333 bool,
334 is_swappable<T, U>::value &&
335 ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
336 detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
337 (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
338 detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))>
339{};
340#endif
341#endif
342
343// std::void_t from C++17
344template<class...>
345struct voider
346{
347 using type = void;
348};
349template<class... Ts>
350using void_t = typename voider<Ts...>::type;
351
352// Trait for checking if a type is a tl::optional
353template<class T>
354struct is_optional_impl : std::false_type
355{};
356template<class T>
357struct is_optional_impl<optional<T>> : std::true_type
358{};
359template<class T>
361
362// Change void to tl::monostate
363template<class U>
365
366template<class F, class U, class = invoke_result_t<F, U>>
368
369// Check if invoking F for some Us returns void
370template<class F, class = void, class... U>
372template<class F, class... U>
373struct returns_void_impl<F, void_t<invoke_result_t<F, U...>>, U...>
374 : std::is_void<invoke_result_t<F, U...>>
375{};
376template<class F, class... U>
377using returns_void = returns_void_impl<F, void, U...>;
378
379template<class T, class... U>
380using enable_if_ret_void = enable_if_t<returns_void<T&&, U...>::value>;
381
382template<class T, class... U>
383using disable_if_ret_void = enable_if_t<!returns_void<T&&, U...>::value>;
384
385template<class T, class U>
388 !std::is_same<detail::decay_t<U>, in_place_t>::value &&
389 !std::is_same<optional<T>, detail::decay_t<U>>::value>;
390
391template<class T, class U, class Other>
394 !std::is_constructible<T, optional<U>&>::value &&
395 !std::is_constructible<T, optional<U>&&>::value &&
396 !std::is_constructible<T, const optional<U>&>::value &&
397 !std::is_constructible<T, const optional<U>&&>::value &&
398 !std::is_convertible<optional<U>&, T>::value &&
399 !std::is_convertible<optional<U>&&, T>::value &&
400 !std::is_convertible<const optional<U>&, T>::value &&
401 !std::is_convertible<const optional<U>&&, T>::value>;
402
403template<class T, class U>
405 !std::is_same<optional<T>, detail::decay_t<U>>::value &&
407 std::is_same<T, detail::decay_t<U>>>::value &&
408 std::is_constructible<T, U>::value && std::is_assignable<T&, U>::value>;
409
410template<class T, class U, class Other>
413 std::is_assignable<T&, Other>::value &&
414 !std::is_constructible<T, optional<U>&>::value &&
415 !std::is_constructible<T, optional<U>&&>::value &&
416 !std::is_constructible<T, const optional<U>&>::value &&
417 !std::is_constructible<T, const optional<U>&&>::value &&
418 !std::is_convertible<optional<U>&, T>::value &&
419 !std::is_convertible<optional<U>&&, T>::value &&
420 !std::is_convertible<const optional<U>&, T>::value &&
421 !std::is_convertible<const optional<U>&&, T>::value &&
422 !std::is_assignable<T&, optional<U>&>::value &&
423 !std::is_assignable<T&, optional<U>&&>::value &&
424 !std::is_assignable<T&, const optional<U>&>::value &&
425 !std::is_assignable<T&, const optional<U>&&>::value>;
426
427// The storage base manages the actual storage, and correctly propagates
428// trivial destruction from T. This case is for when T is not trivially
429// destructible.
430template<class T, bool = ::std::is_trivially_destructible<T>::value>
432{
434 : m_dummy()
435 , m_has_value(false)
436 {
437 }
438
439 template<class... U>
441 : m_value(std::forward<U>(u)...)
442 , m_has_value(true)
443 {
444 }
445
447 {
448 if (m_has_value) {
449 m_value.~T();
450 m_has_value = false;
451 }
452 }
453
454 struct dummy
455 {};
456 union
457 {
460 };
461
463};
464
465// This case is for when T is trivially destructible.
466template<class T>
468{
470 : m_dummy()
471 , m_has_value(false)
472 {
473 }
474
475 template<class... U>
477 : m_value(std::forward<U>(u)...)
478 , m_has_value(true)
479 {
480 }
481
482 // No destructor, so this class is trivially destructible
483
484 struct dummy
485 {};
486 union
487 {
488 dummy m_dummy;
490 };
491
492 bool m_has_value = false;
493};
494
495// This base class provides some handy member functions which can be used in
496// further derived classes
497template<class T>
499{
501
502 void hard_reset() noexcept
503 {
504 get().~T();
505 this->m_has_value = false;
506 }
507
508 template<class... Args>
509 void construct(Args&&... args)
510 {
511 new (std::addressof(this->m_value)) T(std::forward<Args>(args)...);
512 this->m_has_value = true;
513 }
514
515 template<class Opt>
516 void assign(Opt&& rhs)
517 {
518 if (this->has_value()) {
519 if (rhs.has_value()) {
520 this->m_value = std::forward<Opt>(rhs).get();
521 } else {
522 this->m_value.~T();
523 this->m_has_value = false;
524 }
525 }
526
527 else if (rhs.has_value()) {
528 construct(std::forward<Opt>(rhs).get());
529 }
530 }
531
532 bool has_value() const { return this->m_has_value; }
533
534 TL_OPTIONAL_11_CONSTEXPR T& get() & { return this->m_value; }
535 TL_OPTIONAL_11_CONSTEXPR const T& get() const& { return this->m_value; }
536 TL_OPTIONAL_11_CONSTEXPR T&& get() && { return std::move(this->m_value); }
537#ifndef TL_OPTIONAL_NO_CONSTRR
538 constexpr const T&& get() const&& { return std::move(this->m_value); }
539#endif
540};
541
542// This class manages conditionally having a trivial copy constructor
543// This specialization is for when T is trivially copy constructible
544template<class T, bool = TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>
546{
547 using optional_operations_base<T>::optional_operations_base;
548};
549
550// This specialization is for when T is not trivially copy constructible
551template<class T>
553{
554 using optional_operations_base<T>::optional_operations_base;
555
559 {
560 if (rhs.has_value()) {
561 this->construct(rhs.get());
562 } else {
563 this->m_has_value = false;
564 }
565 }
566
570};
571
572// This class manages conditionally having a trivial move constructor
573// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
574// doesn't implement an analogue to std::is_trivially_move_constructible. We
575// have to make do with a non-trivial move constructor even if T is trivially
576// move constructible
577#ifndef TL_OPTIONAL_GCC49
578template<class T, bool = std::is_trivially_move_constructible<T>::value>
580{
581 using optional_copy_base<T>::optional_copy_base;
582};
583#else
584template<class T, bool = false>
585struct optional_move_base;
586#endif
587template<class T>
589{
590 using optional_copy_base<T>::optional_copy_base;
591
594
596 std::is_nothrow_move_constructible<T>::value)
597 {
598 if (rhs.has_value()) {
599 this->construct(std::move(rhs.get()));
600 } else {
601 this->m_has_value = false;
602 }
603 }
606};
607
608// This class manages conditionally having a trivial copy assignment operator
609template<class T,
614{
615 using optional_move_base<T>::optional_move_base;
616};
617
618template<class T>
620{
621 using optional_move_base<T>::optional_move_base;
622
625
628 {
629 this->assign(rhs);
630 return *this;
631 }
633 default;
634};
635
636// This class manages conditionally having a trivial move assignment operator
637// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
638// doesn't implement an analogue to std::is_trivially_move_assignable. We have
639// to make do with a non-trivial move assignment operator even if T is trivially
640// move assignable
641#ifndef TL_OPTIONAL_GCC49
642template<class T,
643 bool = std::is_trivially_destructible<T>::value &&
644 std::is_trivially_move_constructible<T>::value &&
645 std::is_trivially_move_assignable<T>::value>
647{
648 using optional_copy_assign_base<T>::optional_copy_assign_base;
649};
650#else
651template<class T, bool = false>
653#endif
654
655template<class T>
657{
658 using optional_copy_assign_base<T>::optional_copy_assign_base;
659
662
664
666 default;
667
670 std::is_nothrow_move_constructible<T>::value &&
671 std::is_nothrow_move_assignable<T>::value)
672 {
673 this->assign(std::move(rhs));
674 return *this;
675 }
676};
677
678// optional_delete_ctor_base will conditionally delete copy and move
679// constructors depending on whether T is copy/move constructible
680template<class T,
681 bool EnableCopy = std::is_copy_constructible<T>::value,
682 bool EnableMove = std::is_move_constructible<T>::value>
693
694template<class T>
705
706template<class T>
717
718template<class T>
729
730// optional_delete_assign_base will conditionally delete copy and move
731// constructors depending on whether T is copy/move constructible + assignable
732template<class T,
733 bool EnableCopy = (std::is_copy_constructible<T>::value &&
734 std::is_copy_assignable<T>::value),
735 bool EnableMove = (std::is_move_constructible<T>::value &&
736 std::is_move_assignable<T>::value)>
747
748template<class T>
759
760template<class T>
771
772template<class T>
783
784} // namespace detail
785
788{
790 {};
791 constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept {}
792};
796
797class bad_optional_access : public std::exception
798{
799public:
801 const char* what() const noexcept { return "Optional has no value"; }
802};
803
810template<class T>
815{
817
818 static_assert(!std::is_same<T, in_place_t>::value,
819 "instantiation of optional with in_place_t is ill-formed");
820 static_assert(!std::is_same<detail::decay_t<T>, nullopt_t>::value,
821 "instantiation of optional with nullopt_t is ill-formed");
822
823public:
824// The different versions for C++14 and 11 are needed because deduced return
825// types are not SFINAE-safe. This provides better support for things like
826// generic lambdas. C.f.
827// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html
828#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \
829 !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55)
832 template<class F>
833 TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) &
834 {
835 using result = detail::invoke_result_t<F, T&>;
837 "F must return an optional");
838
839 return has_value() ? detail::invoke(std::forward<F>(f), **this)
840 : result(nullopt);
841 }
842
843 template<class F>
844 TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) &&
845 {
846 using result = detail::invoke_result_t<F, T&&>;
848 "F must return an optional");
849
850 return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
851 : result(nullopt);
852 }
853
854 template<class F>
855 constexpr auto and_then(F&& f) const&
856 {
859 "F must return an optional");
860
861 return has_value() ? detail::invoke(std::forward<F>(f), **this)
862 : result(nullopt);
863 }
864
865#ifndef TL_OPTIONAL_NO_CONSTRR
866 template<class F>
867 constexpr auto and_then(F&& f) const&&
868 {
871 "F must return an optional");
872
873 return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
874 : result(nullopt);
875 }
876#endif
877#else
880 template<class F>
882 {
883 using result = detail::invoke_result_t<F, T&>;
885 "F must return an optional");
886
887 return has_value() ? detail::invoke(std::forward<F>(f), **this)
888 : result(nullopt);
889 }
890
891 template<class F>
893 {
894 using result = detail::invoke_result_t<F, T&&>;
896 "F must return an optional");
897
898 return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
899 : result(nullopt);
900 }
901
902 template<class F>
904 {
907 "F must return an optional");
908
909 return has_value() ? detail::invoke(std::forward<F>(f), **this)
910 : result(nullopt);
911 }
912
913#ifndef TL_OPTIONAL_NO_CONSTRR
914 template<class F>
916 {
919 "F must return an optional");
920
921 return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
922 : result(nullopt);
923 }
924#endif
925#endif
926
927#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \
928 !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55)
930 template<class F>
931 TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) &
932 {
933 return optional_map_impl(*this, std::forward<F>(f));
934 }
935
936 template<class F>
937 TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) &&
938 {
939 return optional_map_impl(std::move(*this), std::forward<F>(f));
940 }
941
942 template<class F>
943 constexpr auto map(F&& f) const&
944 {
945 return optional_map_impl(*this, std::forward<F>(f));
946 }
947
948 template<class F>
949 constexpr auto map(F&& f) const&&
950 {
951 return optional_map_impl(std::move(*this), std::forward<F>(f));
952 }
953#else
955 template<class F>
956 TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval<optional&>(),
957 std::declval<F&&>()))
958 map(F&& f) &
959 {
960 return optional_map_impl(*this, std::forward<F>(f));
961 }
962
963 template<class F>
964 TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(
965 std::declval<optional&&>(),
966 std::declval<F&&>()))
967 map(F&& f) &&
968 {
969 return optional_map_impl(std::move(*this), std::forward<F>(f));
970 }
971
972 template<class F>
973 constexpr decltype(optional_map_impl(std::declval<const optional&>(),
974 std::declval<F&&>()))
975 map(F&& f) const&
976 {
977 return optional_map_impl(*this, std::forward<F>(f));
978 }
979
980#ifndef TL_OPTIONAL_NO_CONSTRR
981 template<class F>
982 constexpr decltype(optional_map_impl(std::declval<const optional&&>(),
983 std::declval<F&&>()))
984 map(F&& f) const&&
985 {
986 return optional_map_impl(std::move(*this), std::forward<F>(f));
987 }
988#endif
989#endif
990
991#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \
992 !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55)
994 template<class F>
995 TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) &
996 {
997 return optional_map_impl(*this, std::forward<F>(f));
998 }
999
1000 template<class F>
1001 TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) &&
1002 {
1003 return optional_map_impl(std::move(*this), std::forward<F>(f));
1004 }
1005
1006 template<class F>
1007 constexpr auto transform(F&& f) const&
1008 {
1009 return optional_map_impl(*this, std::forward<F>(f));
1010 }
1011
1012 template<class F>
1013 constexpr auto transform(F&& f) const&&
1014 {
1015 return optional_map_impl(std::move(*this), std::forward<F>(f));
1016 }
1017#else
1019 template<class F>
1020 TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval<optional&>(),
1021 std::declval<F&&>()))
1022 transform(F&& f) &
1023 {
1024 return optional_map_impl(*this, std::forward<F>(f));
1025 }
1026
1027 template<class F>
1028 TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(
1029 std::declval<optional&&>(),
1030 std::declval<F&&>()))
1031 transform(F&& f) &&
1032 {
1033 return optional_map_impl(std::move(*this), std::forward<F>(f));
1034 }
1035
1036 template<class F>
1037 constexpr decltype(optional_map_impl(std::declval<const optional&>(),
1038 std::declval<F&&>()))
1039 transform(F&& f) const&
1040 {
1041 return optional_map_impl(*this, std::forward<F>(f));
1042 }
1043
1044#ifndef TL_OPTIONAL_NO_CONSTRR
1045 template<class F>
1046 constexpr decltype(optional_map_impl(std::declval<const optional&&>(),
1047 std::declval<F&&>()))
1048 transform(F&& f) const&&
1049 {
1050 return optional_map_impl(std::move(*this), std::forward<F>(f));
1051 }
1052#endif
1053#endif
1054
1056 template<class F, detail::enable_if_ret_void<F>* = nullptr>
1058 {
1059 if (has_value())
1060 return *this;
1061
1062 std::forward<F>(f)();
1063 return nullopt;
1064 }
1065
1066 template<class F, detail::disable_if_ret_void<F>* = nullptr>
1068 {
1069 return has_value() ? *this : std::forward<F>(f)();
1070 }
1071
1072 template<class F, detail::enable_if_ret_void<F>* = nullptr>
1074 {
1075 if (has_value())
1076 return std::move(*this);
1077
1078 std::forward<F>(f)();
1079 return nullopt;
1080 }
1081
1082 template<class F, detail::disable_if_ret_void<F>* = nullptr>
1084 {
1085 return has_value() ? std::move(*this) : std::forward<F>(f)();
1086 }
1087
1088 template<class F, detail::enable_if_ret_void<F>* = nullptr>
1089 optional<T> or_else(F&& f) const&
1090 {
1091 if (has_value())
1092 return *this;
1093
1094 std::forward<F>(f)();
1095 return nullopt;
1096 }
1097
1098 template<class F, detail::disable_if_ret_void<F>* = nullptr>
1100 {
1101 return has_value() ? *this : std::forward<F>(f)();
1102 }
1103
1104#ifndef TL_OPTIONAL_NO_CONSTRR
1105 template<class F, detail::enable_if_ret_void<F>* = nullptr>
1106 optional<T> or_else(F&& f) const&&
1107 {
1108 if (has_value())
1109 return std::move(*this);
1110
1111 std::forward<F>(f)();
1112 return nullopt;
1113 }
1114
1115 template<class F, detail::disable_if_ret_void<F>* = nullptr>
1116 optional<T> or_else(F&& f) const&&
1117 {
1118 return has_value() ? std::move(*this) : std::forward<F>(f)();
1119 }
1120#endif
1121
1123 template<class F, class U>
1124 U map_or(F&& f, U&& u) &
1125 {
1126 return has_value() ? detail::invoke(std::forward<F>(f), **this)
1127 : std::forward<U>(u);
1128 }
1129
1130 template<class F, class U>
1131 U map_or(F&& f, U&& u) &&
1132 {
1133 return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
1134 : std::forward<U>(u);
1135 }
1136
1137 template<class F, class U>
1138 U map_or(F&& f, U&& u) const&
1139 {
1140 return has_value() ? detail::invoke(std::forward<F>(f), **this)
1141 : std::forward<U>(u);
1142 }
1143
1144#ifndef TL_OPTIONAL_NO_CONSTRR
1145 template<class F, class U>
1146 U map_or(F&& f, U&& u) const&&
1147 {
1148 return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
1149 : std::forward<U>(u);
1150 }
1151#endif
1152
1155 template<class F, class U>
1157 {
1158 return has_value() ? detail::invoke(std::forward<F>(f), **this)
1159 : std::forward<U>(u)();
1160 }
1161
1162 template<class F, class U>
1164 {
1165 return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
1166 : std::forward<U>(u)();
1167 }
1168
1169 template<class F, class U>
1171 {
1172 return has_value() ? detail::invoke(std::forward<F>(f), **this)
1173 : std::forward<U>(u)();
1174 }
1175
1176#ifndef TL_OPTIONAL_NO_CONSTRR
1177 template<class F, class U>
1179 {
1180 return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
1181 : std::forward<U>(u)();
1182 }
1183#endif
1184
1186 template<class U>
1188 {
1189 using result = optional<detail::decay_t<U>>;
1190 return has_value() ? result{ u } : result{ nullopt };
1191 }
1192
1195 {
1196 return has_value() ? *this : rhs;
1197 }
1198
1199 constexpr optional disjunction(const optional& rhs) const&
1200 {
1201 return has_value() ? *this : rhs;
1202 }
1203
1205 {
1206 return has_value() ? std::move(*this) : rhs;
1207 }
1208
1209#ifndef TL_OPTIONAL_NO_CONSTRR
1210 constexpr optional disjunction(const optional& rhs) const&&
1211 {
1212 return has_value() ? std::move(*this) : rhs;
1213 }
1214#endif
1215
1217 {
1218 return has_value() ? *this : std::move(rhs);
1219 }
1220
1221 constexpr optional disjunction(optional&& rhs) const&
1222 {
1223 return has_value() ? *this : std::move(rhs);
1224 }
1225
1227 {
1228 return has_value() ? std::move(*this) : std::move(rhs);
1229 }
1230
1231#ifndef TL_OPTIONAL_NO_CONSTRR
1232 constexpr optional disjunction(optional&& rhs) const&&
1233 {
1234 return has_value() ? std::move(*this) : std::move(rhs);
1235 }
1236#endif
1237
1240 {
1241 optional ret = std::move(*this);
1242 reset();
1243 return ret;
1244 }
1245
1246 using value_type = T;
1247
1249 constexpr optional() noexcept = default;
1250
1251 constexpr optional(nullopt_t) noexcept {}
1252
1258
1264
1266 template<class... Args>
1267 constexpr explicit optional(
1268 detail::enable_if_t<std::is_constructible<T, Args...>::value, in_place_t>,
1269 Args&&... args)
1270 : base(in_place, std::forward<Args>(args)...)
1271 {
1272 }
1273
1274 template<class U, class... Args>
1277 std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value,
1278 in_place_t>,
1279 std::initializer_list<U> il,
1280 Args&&... args)
1281 {
1282 this->construct(il, std::forward<Args>(args)...);
1283 }
1284
1286 template<class U = T,
1289 constexpr optional(U&& u)
1290 : base(in_place, std::forward<U>(u))
1291 {
1292 }
1293
1294 template<class U = T,
1297 constexpr explicit optional(U&& u)
1298 : base(in_place, std::forward<U>(u))
1299 {
1300 }
1301
1303 template<
1304 class U,
1308 {
1309 if (rhs.has_value()) {
1310 this->construct(*rhs);
1311 }
1312 }
1313
1314 template<
1315 class U,
1318 explicit optional(const optional<U>& rhs)
1319 {
1320 if (rhs.has_value()) {
1321 this->construct(*rhs);
1322 }
1323 }
1324
1326 template<class U,
1330 {
1331 if (rhs.has_value()) {
1332 this->construct(std::move(*rhs));
1333 }
1334 }
1335
1336 template<class U,
1339 explicit optional(optional<U>&& rhs)
1340 {
1341 if (rhs.has_value()) {
1342 this->construct(std::move(*rhs));
1343 }
1344 }
1345
1347 ~optional() = default;
1348
1353 {
1354 if (has_value()) {
1355 this->m_value.~T();
1356 this->m_has_value = false;
1357 }
1358
1359 return *this;
1360 }
1361
1366 optional& operator=(const optional& rhs) = default;
1367
1372 optional& operator=(optional&& rhs) = default;
1373
1376 template<class U = T, detail::enable_assign_forward<T, U>* = nullptr>
1378 {
1379 if (has_value()) {
1380 this->m_value = std::forward<U>(u);
1381 } else {
1382 this->construct(std::forward<U>(u));
1383 }
1384
1385 return *this;
1386 }
1387
1392 template<class U, detail::enable_assign_from_other<T, U, const U&>* = nullptr>
1394 {
1395 if (has_value()) {
1396 if (rhs.has_value()) {
1397 this->m_value = *rhs;
1398 } else {
1399 this->hard_reset();
1400 }
1401 }
1402
1403 else if (rhs.has_value()) {
1404 this->construct(*rhs);
1405 }
1406
1407 return *this;
1408 }
1409
1410 // TODO check exception guarantee
1415 template<class U, detail::enable_assign_from_other<T, U, U>* = nullptr>
1417 {
1418 if (has_value()) {
1419 if (rhs.has_value()) {
1420 this->m_value = std::move(*rhs);
1421 } else {
1422 this->hard_reset();
1423 }
1424 }
1425
1426 else if (rhs.has_value()) {
1427 this->construct(std::move(*rhs));
1428 }
1429
1430 return *this;
1431 }
1432
1435 template<class... Args>
1436 T& emplace(Args&&... args)
1437 {
1438 static_assert(std::is_constructible<T, Args&&...>::value,
1439 "T must be constructible with Args");
1440
1441 *this = nullopt;
1442 this->construct(std::forward<Args>(args)...);
1443 return value();
1444 }
1445
1446 template<class U, class... Args>
1448 std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value,
1449 T&>
1450 emplace(std::initializer_list<U> il, Args&&... args)
1451 {
1452 *this = nullopt;
1453 this->construct(il, std::forward<Args>(args)...);
1454 return value();
1455 }
1456
1463 void swap(optional& rhs) noexcept(
1464 std::is_nothrow_move_constructible<T>::value &&
1466 {
1467 using std::swap;
1468 if (has_value()) {
1469 if (rhs.has_value()) {
1470 swap(**this, *rhs);
1471 } else {
1472 new (std::addressof(rhs.m_value)) T(std::move(this->m_value));
1473 this->m_value.T::~T();
1474 }
1475 } else if (rhs.has_value()) {
1476 new (std::addressof(this->m_value)) T(std::move(rhs.m_value));
1477 rhs.m_value.T::~T();
1478 }
1479 swap(this->m_has_value, rhs.m_has_value);
1480 }
1481
1483 constexpr const T* operator->() const
1484 {
1485 return std::addressof(this->m_value);
1486 }
1487
1489 {
1490 return std::addressof(this->m_value);
1491 }
1492
1494 TL_OPTIONAL_11_CONSTEXPR T& operator*() & { return this->m_value; }
1495
1496 constexpr const T& operator*() const& { return this->m_value; }
1497
1499 {
1500 return std::move(this->m_value);
1501 }
1502
1503#ifndef TL_OPTIONAL_NO_CONSTRR
1504 constexpr const T&& operator*() const&& { return std::move(this->m_value); }
1505#endif
1506
1508 constexpr bool has_value() const noexcept { return this->m_has_value; }
1509
1510 constexpr explicit operator bool() const noexcept
1511 {
1512 return this->m_has_value;
1513 }
1514
1518 {
1519 if (has_value())
1520 return this->m_value;
1521 throw bad_optional_access();
1522 }
1524 {
1525 if (has_value())
1526 return this->m_value;
1527 throw bad_optional_access();
1528 }
1530 {
1531 if (has_value())
1532 return std::move(this->m_value);
1533 throw bad_optional_access();
1534 }
1535
1536#ifndef TL_OPTIONAL_NO_CONSTRR
1538 {
1539 if (has_value())
1540 return std::move(this->m_value);
1541 throw bad_optional_access();
1542 }
1543#endif
1544
1546 template<class U>
1547 constexpr T value_or(U&& u) const&
1548 {
1549 static_assert(std::is_copy_constructible<T>::value &&
1550 std::is_convertible<U&&, T>::value,
1551 "T must be copy constructible and convertible from U");
1552 return has_value() ? **this : static_cast<T>(std::forward<U>(u));
1553 }
1554
1555 template<class U>
1557 {
1558 static_assert(std::is_move_constructible<T>::value &&
1559 std::is_convertible<U&&, T>::value,
1560 "T must be move constructible and convertible from U");
1561 return has_value() ? std::move(**this) : static_cast<T>(std::forward<U>(u));
1562 }
1563
1565 void reset() noexcept
1566 {
1567 if (has_value()) {
1568 this->m_value.~T();
1569 this->m_has_value = false;
1570 }
1571 }
1572}; // namespace tl
1573
1575template<class T, class U>
1576inline constexpr bool
1577operator==(const optional<T>& lhs, const optional<U>& rhs)
1578{
1579 return lhs.has_value() == rhs.has_value() &&
1580 (!lhs.has_value() || *lhs == *rhs);
1581}
1582template<class T, class U>
1583inline constexpr bool
1584operator!=(const optional<T>& lhs, const optional<U>& rhs)
1585{
1586 return lhs.has_value() != rhs.has_value() ||
1587 (lhs.has_value() && *lhs != *rhs);
1588}
1589template<class T, class U>
1590inline constexpr bool
1591operator<(const optional<T>& lhs, const optional<U>& rhs)
1592{
1593 return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs);
1594}
1595template<class T, class U>
1596inline constexpr bool
1597operator>(const optional<T>& lhs, const optional<U>& rhs)
1598{
1599 return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs);
1600}
1601template<class T, class U>
1602inline constexpr bool
1603operator<=(const optional<T>& lhs, const optional<U>& rhs)
1604{
1605 return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs);
1606}
1607template<class T, class U>
1608inline constexpr bool
1609operator>=(const optional<T>& lhs, const optional<U>& rhs)
1610{
1611 return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs);
1612}
1613
1615template<class T>
1616inline constexpr bool
1617operator==(const optional<T>& lhs, nullopt_t) noexcept
1618{
1619 return !lhs.has_value();
1620}
1621template<class T>
1622inline constexpr bool
1623operator==(nullopt_t, const optional<T>& rhs) noexcept
1624{
1625 return !rhs.has_value();
1626}
1627template<class T>
1628inline constexpr bool
1629operator!=(const optional<T>& lhs, nullopt_t) noexcept
1630{
1631 return lhs.has_value();
1632}
1633template<class T>
1634inline constexpr bool
1635operator!=(nullopt_t, const optional<T>& rhs) noexcept
1636{
1637 return rhs.has_value();
1638}
1639template<class T>
1640inline constexpr bool
1641operator<(const optional<T>&, nullopt_t) noexcept
1642{
1643 return false;
1644}
1645template<class T>
1646inline constexpr bool
1647operator<(nullopt_t, const optional<T>& rhs) noexcept
1648{
1649 return rhs.has_value();
1650}
1651template<class T>
1652inline constexpr bool
1653operator<=(const optional<T>& lhs, nullopt_t) noexcept
1654{
1655 return !lhs.has_value();
1656}
1657template<class T>
1658inline constexpr bool
1659operator<=(nullopt_t, const optional<T>&) noexcept
1660{
1661 return true;
1662}
1663template<class T>
1664inline constexpr bool
1665operator>(const optional<T>& lhs, nullopt_t) noexcept
1666{
1667 return lhs.has_value();
1668}
1669template<class T>
1670inline constexpr bool
1672{
1673 return false;
1674}
1675template<class T>
1676inline constexpr bool
1678{
1679 return true;
1680}
1681template<class T>
1682inline constexpr bool
1683operator>=(nullopt_t, const optional<T>& rhs) noexcept
1684{
1685 return !rhs.has_value();
1686}
1687
1689template<class T, class U>
1690inline constexpr bool
1691operator==(const optional<T>& lhs, const U& rhs)
1692{
1693 return lhs.has_value() ? *lhs == rhs : false;
1694}
1695template<class T, class U>
1696inline constexpr bool
1697operator==(const U& lhs, const optional<T>& rhs)
1698{
1699 return rhs.has_value() ? lhs == *rhs : false;
1700}
1701template<class T, class U>
1702inline constexpr bool
1703operator!=(const optional<T>& lhs, const U& rhs)
1704{
1705 return lhs.has_value() ? *lhs != rhs : true;
1706}
1707template<class T, class U>
1708inline constexpr bool
1709operator!=(const U& lhs, const optional<T>& rhs)
1710{
1711 return rhs.has_value() ? lhs != *rhs : true;
1712}
1713template<class T, class U>
1714inline constexpr bool
1715operator<(const optional<T>& lhs, const U& rhs)
1716{
1717 return lhs.has_value() ? *lhs < rhs : true;
1718}
1719template<class T, class U>
1720inline constexpr bool
1721operator<(const U& lhs, const optional<T>& rhs)
1722{
1723 return rhs.has_value() ? lhs < *rhs : false;
1724}
1725template<class T, class U>
1726inline constexpr bool
1727operator<=(const optional<T>& lhs, const U& rhs)
1728{
1729 return lhs.has_value() ? *lhs <= rhs : true;
1730}
1731template<class T, class U>
1732inline constexpr bool
1733operator<=(const U& lhs, const optional<T>& rhs)
1734{
1735 return rhs.has_value() ? lhs <= *rhs : false;
1736}
1737template<class T, class U>
1738inline constexpr bool
1739operator>(const optional<T>& lhs, const U& rhs)
1740{
1741 return lhs.has_value() ? *lhs > rhs : false;
1742}
1743template<class T, class U>
1744inline constexpr bool
1745operator>(const U& lhs, const optional<T>& rhs)
1746{
1747 return rhs.has_value() ? lhs > *rhs : true;
1748}
1749template<class T, class U>
1750inline constexpr bool
1751operator>=(const optional<T>& lhs, const U& rhs)
1752{
1753 return lhs.has_value() ? *lhs >= rhs : false;
1754}
1755template<class T, class U>
1756inline constexpr bool
1757operator>=(const U& lhs, const optional<T>& rhs)
1758{
1759 return rhs.has_value() ? lhs >= *rhs : true;
1760}
1761
1762template<class T,
1763 detail::enable_if_t<std::is_move_constructible<T>::value>* = nullptr,
1764 detail::enable_if_t<detail::is_swappable<T>::value>* = nullptr>
1765void
1766swap(optional<T>& lhs, optional<T>& rhs) noexcept(noexcept(lhs.swap(rhs)))
1767{
1768 return lhs.swap(rhs);
1769}
1770
1771namespace detail {
1773{};
1774} // namespace detail
1775
1776template<
1777 class T = detail::i_am_secret,
1778 class U,
1781 T>>
1782inline constexpr optional<Ret>
1784{
1785 return optional<Ret>(std::forward<U>(v));
1786}
1787
1788template<class T, class... Args>
1789inline constexpr optional<T>
1790make_optional(Args&&... args)
1791{
1792 return optional<T>(in_place, std::forward<Args>(args)...);
1793}
1794template<class T, class U, class... Args>
1795inline constexpr optional<T>
1796make_optional(std::initializer_list<U> il, Args&&... args)
1797{
1798 return optional<T>(in_place, il, std::forward<Args>(args)...);
1799}
1800
1801#if __cplusplus >= 201703L
1802template<class T>
1803optional(T) -> optional<T>;
1804#endif
1805
1807namespace detail {
1808#ifdef TL_OPTIONAL_CXX14
1809template<class Opt,
1810 class F,
1811 class Ret = decltype(detail::invoke(std::declval<F>(),
1812 *std::declval<Opt>())),
1813 detail::enable_if_t<!std::is_void<Ret>::value>* = nullptr>
1814constexpr auto
1815optional_map_impl(Opt&& opt, F&& f)
1816{
1817 return opt.has_value()
1818 ? detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt))
1819 : optional<Ret>(nullopt);
1820}
1821
1822template<class Opt,
1823 class F,
1824 class Ret = decltype(detail::invoke(std::declval<F>(),
1825 *std::declval<Opt>())),
1826 detail::enable_if_t<std::is_void<Ret>::value>* = nullptr>
1827auto
1828optional_map_impl(Opt&& opt, F&& f)
1829{
1830 if (opt.has_value()) {
1831 detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt));
1832 return make_optional(monostate{});
1833 }
1834
1835 return optional<monostate>(nullopt);
1836}
1837#else
1838template<class Opt,
1839 class F,
1840 class Ret = decltype(detail::invoke(std::declval<F>(),
1841 *std::declval<Opt>())),
1842 detail::enable_if_t<!std::is_void<Ret>::value>* = nullptr>
1843
1844constexpr auto
1846{
1847 return opt.has_value()
1848 ? detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt))
1849 : optional<Ret>(nullopt);
1850}
1851
1852template<class Opt,
1853 class F,
1854 class Ret = decltype(detail::invoke(std::declval<F>(),
1855 *std::declval<Opt>())),
1856 detail::enable_if_t<std::is_void<Ret>::value>* = nullptr>
1857
1858auto
1860{
1861 if (opt.has_value()) {
1862 detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt));
1863 return monostate{};
1864 }
1865
1866 return nullopt;
1867}
1868#endif
1869} // namespace detail
1870
1873template<class T>
1875{
1876public:
1877// The different versions for C++14 and 11 are needed because deduced return
1878// types are not SFINAE-safe. This provides better support for things like
1879// generic lambdas. C.f.
1880// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html
1881#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \
1882 !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55)
1883
1886 template<class F>
1887 TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) &
1888 {
1889 using result = detail::invoke_result_t<F, T&>;
1891 "F must return an optional");
1892
1893 return has_value() ? detail::invoke(std::forward<F>(f), **this)
1894 : result(nullopt);
1895 }
1896
1897 template<class F>
1898 TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) &&
1899 {
1900 using result = detail::invoke_result_t<F, T&>;
1902 "F must return an optional");
1903
1904 return has_value() ? detail::invoke(std::forward<F>(f), **this)
1905 : result(nullopt);
1906 }
1907
1908 template<class F>
1909 constexpr auto and_then(F&& f) const&
1910 {
1913 "F must return an optional");
1914
1915 return has_value() ? detail::invoke(std::forward<F>(f), **this)
1916 : result(nullopt);
1917 }
1918
1919#ifndef TL_OPTIONAL_NO_CONSTRR
1920 template<class F>
1921 constexpr auto and_then(F&& f) const&&
1922 {
1925 "F must return an optional");
1926
1927 return has_value() ? detail::invoke(std::forward<F>(f), **this)
1928 : result(nullopt);
1929 }
1930#endif
1931#else
1934 template<class F>
1936 {
1937 using result = detail::invoke_result_t<F, T&>;
1939 "F must return an optional");
1940
1941 return has_value() ? detail::invoke(std::forward<F>(f), **this)
1942 : result(nullopt);
1943 }
1944
1945 template<class F>
1947 {
1948 using result = detail::invoke_result_t<F, T&>;
1950 "F must return an optional");
1951
1952 return has_value() ? detail::invoke(std::forward<F>(f), **this)
1953 : result(nullopt);
1954 }
1955
1956 template<class F>
1958 {
1961 "F must return an optional");
1962
1963 return has_value() ? detail::invoke(std::forward<F>(f), **this)
1964 : result(nullopt);
1965 }
1966
1967#ifndef TL_OPTIONAL_NO_CONSTRR
1968 template<class F>
1970 {
1973 "F must return an optional");
1974
1975 return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
1976 : result(nullopt);
1977 }
1978#endif
1979#endif
1980
1981#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \
1982 !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55)
1984 template<class F>
1985 TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) &
1986 {
1987 return detail::optional_map_impl(*this, std::forward<F>(f));
1988 }
1989
1990 template<class F>
1991 TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) &&
1992 {
1993 return detail::optional_map_impl(std::move(*this), std::forward<F>(f));
1994 }
1995
1996 template<class F>
1997 constexpr auto map(F&& f) const&
1998 {
1999 return detail::optional_map_impl(*this, std::forward<F>(f));
2000 }
2001
2002 template<class F>
2003 constexpr auto map(F&& f) const&&
2004 {
2005 return detail::optional_map_impl(std::move(*this), std::forward<F>(f));
2006 }
2007#else
2009 template<class F>
2011 std::declval<optional&>(),
2012 std::declval<F&&>()))
2013 map(F&& f) &
2014 {
2015 return detail::optional_map_impl(*this, std::forward<F>(f));
2016 }
2017
2018 template<class F>
2020 std::declval<optional&&>(),
2021 std::declval<F&&>()))
2022 map(F&& f) &&
2023 {
2024 return detail::optional_map_impl(std::move(*this), std::forward<F>(f));
2025 }
2026
2027 template<class F>
2028 constexpr decltype(detail::optional_map_impl(std::declval<const optional&>(),
2029 std::declval<F&&>()))
2030 map(F&& f) const&
2031 {
2032 return detail::optional_map_impl(*this, std::forward<F>(f));
2033 }
2034
2035#ifndef TL_OPTIONAL_NO_CONSTRR
2036 template<class F>
2037 constexpr decltype(detail::optional_map_impl(std::declval<const optional&&>(),
2038 std::declval<F&&>()))
2039 map(F&& f) const&&
2040 {
2041 return detail::optional_map_impl(std::move(*this), std::forward<F>(f));
2042 }
2043#endif
2044#endif
2045
2046#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \
2047 !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55)
2049 template<class F>
2050 TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) &
2051 {
2052 return detail::optional_map_impl(*this, std::forward<F>(f));
2053 }
2054
2055 template<class F>
2056 TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) &&
2057 {
2058 return detail::optional_map_impl(std::move(*this), std::forward<F>(f));
2059 }
2060
2061 template<class F>
2062 constexpr auto transform(F&& f) const&
2063 {
2064 return detail::optional_map_impl(*this, std::forward<F>(f));
2065 }
2066
2067 template<class F>
2068 constexpr auto transform(F&& f) const&&
2069 {
2070 return detail::optional_map_impl(std::move(*this), std::forward<F>(f));
2071 }
2072#else
2074 template<class F>
2076 std::declval<optional&>(),
2077 std::declval<F&&>()))
2078 transform(F&& f) &
2079 {
2080 return detail::optional_map_impl(*this, std::forward<F>(f));
2081 }
2082
2085 template<class F>
2087 std::declval<optional&&>(),
2088 std::declval<F&&>()))
2089 transform(F&& f) &&
2090 {
2091 return detail::optional_map_impl(std::move(*this), std::forward<F>(f));
2092 }
2093
2094 template<class F>
2095 constexpr decltype(detail::optional_map_impl(std::declval<const optional&>(),
2096 std::declval<F&&>()))
2097 transform(F&& f) const&
2098 {
2099 return detail::optional_map_impl(*this, std::forward<F>(f));
2100 }
2101
2102#ifndef TL_OPTIONAL_NO_CONSTRR
2103 template<class F>
2104 constexpr decltype(detail::optional_map_impl(std::declval<const optional&&>(),
2105 std::declval<F&&>()))
2106 transform(F&& f) const&&
2107 {
2108 return detail::optional_map_impl(std::move(*this), std::forward<F>(f));
2109 }
2110#endif
2111#endif
2112
2114 template<class F, detail::enable_if_ret_void<F>* = nullptr>
2116 {
2117 if (has_value())
2118 return *this;
2119
2120 std::forward<F>(f)();
2121 return nullopt;
2122 }
2123
2124 template<class F, detail::disable_if_ret_void<F>* = nullptr>
2126 {
2127 return has_value() ? *this : std::forward<F>(f)();
2128 }
2129
2130 template<class F, detail::enable_if_ret_void<F>* = nullptr>
2132 {
2133 if (has_value())
2134 return std::move(*this);
2135
2136 std::forward<F>(f)();
2137 return nullopt;
2138 }
2139
2140 template<class F, detail::disable_if_ret_void<F>* = nullptr>
2142 {
2143 return has_value() ? std::move(*this) : std::forward<F>(f)();
2144 }
2145
2146 template<class F, detail::enable_if_ret_void<F>* = nullptr>
2147 optional<T> or_else(F&& f) const&
2148 {
2149 if (has_value())
2150 return *this;
2151
2152 std::forward<F>(f)();
2153 return nullopt;
2154 }
2155
2156 template<class F, detail::disable_if_ret_void<F>* = nullptr>
2158 {
2159 return has_value() ? *this : std::forward<F>(f)();
2160 }
2161
2162#ifndef TL_OPTIONAL_NO_CONSTRR
2163 template<class F, detail::enable_if_ret_void<F>* = nullptr>
2164 optional<T> or_else(F&& f) const&&
2165 {
2166 if (has_value())
2167 return std::move(*this);
2168
2169 std::forward<F>(f)();
2170 return nullopt;
2171 }
2172
2173 template<class F, detail::disable_if_ret_void<F>* = nullptr>
2174 optional<T> or_else(F&& f) const&&
2175 {
2176 return has_value() ? std::move(*this) : std::forward<F>(f)();
2177 }
2178#endif
2179
2181 template<class F, class U>
2182 U map_or(F&& f, U&& u) &
2183 {
2184 return has_value() ? detail::invoke(std::forward<F>(f), **this)
2185 : std::forward<U>(u);
2186 }
2187
2188 template<class F, class U>
2189 U map_or(F&& f, U&& u) &&
2190 {
2191 return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
2192 : std::forward<U>(u);
2193 }
2194
2195 template<class F, class U>
2196 U map_or(F&& f, U&& u) const&
2197 {
2198 return has_value() ? detail::invoke(std::forward<F>(f), **this)
2199 : std::forward<U>(u);
2200 }
2201
2202#ifndef TL_OPTIONAL_NO_CONSTRR
2203 template<class F, class U>
2204 U map_or(F&& f, U&& u) const&&
2205 {
2206 return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
2207 : std::forward<U>(u);
2208 }
2209#endif
2210
2213 template<class F, class U>
2215 {
2216 return has_value() ? detail::invoke(std::forward<F>(f), **this)
2217 : std::forward<U>(u)();
2218 }
2219
2220 template<class F, class U>
2222 {
2223 return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
2224 : std::forward<U>(u)();
2225 }
2226
2227 template<class F, class U>
2229 {
2230 return has_value() ? detail::invoke(std::forward<F>(f), **this)
2231 : std::forward<U>(u)();
2232 }
2233
2234#ifndef TL_OPTIONAL_NO_CONSTRR
2235 template<class F, class U>
2237 {
2238 return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
2239 : std::forward<U>(u)();
2240 }
2241#endif
2242
2244 template<class U>
2246 {
2247 using result = optional<detail::decay_t<U>>;
2248 return has_value() ? result{ u } : result{ nullopt };
2249 }
2250
2253 {
2254 return has_value() ? *this : rhs;
2255 }
2256
2257 constexpr optional disjunction(const optional& rhs) const&
2258 {
2259 return has_value() ? *this : rhs;
2260 }
2261
2263 {
2264 return has_value() ? std::move(*this) : rhs;
2265 }
2266
2267#ifndef TL_OPTIONAL_NO_CONSTRR
2268 constexpr optional disjunction(const optional& rhs) const&&
2269 {
2270 return has_value() ? std::move(*this) : rhs;
2271 }
2272#endif
2273
2275 {
2276 return has_value() ? *this : std::move(rhs);
2277 }
2278
2279 constexpr optional disjunction(optional&& rhs) const&
2280 {
2281 return has_value() ? *this : std::move(rhs);
2282 }
2283
2285 {
2286 return has_value() ? std::move(*this) : std::move(rhs);
2287 }
2288
2289#ifndef TL_OPTIONAL_NO_CONSTRR
2290 constexpr optional disjunction(optional&& rhs) const&&
2291 {
2292 return has_value() ? std::move(*this) : std::move(rhs);
2293 }
2294#endif
2295
2298 {
2299 optional ret = std::move(*this);
2300 reset();
2301 return ret;
2302 }
2303
2304 using value_type = T&;
2305
2307 constexpr optional() noexcept
2308 : m_value(nullptr)
2309 {
2310 }
2311
2312 constexpr optional(nullopt_t) noexcept
2313 : m_value(nullptr)
2314 {
2315 }
2316
2321 TL_OPTIONAL_11_CONSTEXPR optional(const optional& rhs) noexcept = default;
2322
2328
2330 template<class U = T,
2332 !detail::is_optional<detail::decay_t<U>>::value>* = nullptr>
2333 constexpr optional(U&& u) noexcept
2334 : m_value(std::addressof(u))
2335 {
2336 static_assert(std::is_lvalue_reference<U>::value, "U must be an lvalue");
2337 }
2338
2339 template<class U>
2340 constexpr explicit optional(const optional<U>& rhs) noexcept
2341 : optional(*rhs)
2342 {
2343 }
2344
2346 ~optional() = default;
2347
2352 {
2353 m_value = nullptr;
2354 return *this;
2355 }
2356
2361 optional& operator=(const optional& rhs) = default;
2362
2364 template<class U = T,
2366 !detail::is_optional<detail::decay_t<U>>::value>* = nullptr>
2368 {
2369 static_assert(std::is_lvalue_reference<U>::value, "U must be an lvalue");
2370 m_value = std::addressof(u);
2371 return *this;
2372 }
2373
2378 template<class U>
2379 optional& operator=(const optional<U>& rhs) noexcept
2380 {
2381 m_value = std::addressof(rhs.value());
2382 return *this;
2383 }
2384
2386 template<class U = T,
2388 !detail::is_optional<detail::decay_t<U>>::value>* = nullptr>
2389 optional& emplace(U&& u) noexcept
2390 {
2391 return *this = std::forward<U>(u);
2392 }
2393
2394 void swap(optional& rhs) noexcept { std::swap(m_value, rhs.m_value); }
2395
2397 constexpr const T* operator->() const noexcept { return m_value; }
2398
2399 TL_OPTIONAL_11_CONSTEXPR T* operator->() noexcept { return m_value; }
2400
2402 TL_OPTIONAL_11_CONSTEXPR T& operator*() noexcept { return *m_value; }
2403
2404 constexpr const T& operator*() const noexcept { return *m_value; }
2405
2406 constexpr bool has_value() const noexcept { return m_value != nullptr; }
2407
2408 constexpr explicit operator bool() const noexcept
2409 {
2410 return m_value != nullptr;
2411 }
2412
2416 {
2417 if (has_value())
2418 return *m_value;
2419 throw bad_optional_access();
2420 }
2422 {
2423 if (has_value())
2424 return *m_value;
2425 throw bad_optional_access();
2426 }
2427
2429 template<class U>
2430 constexpr T value_or(U&& u) const& noexcept
2431 {
2432 static_assert(std::is_copy_constructible<T>::value &&
2433 std::is_convertible<U&&, T>::value,
2434 "T must be copy constructible and convertible from U");
2435 return has_value() ? **this : static_cast<T>(std::forward<U>(u));
2436 }
2437
2439 template<class U>
2441 {
2442 static_assert(std::is_move_constructible<T>::value &&
2443 std::is_convertible<U&&, T>::value,
2444 "T must be move constructible and convertible from U");
2445 return has_value() ? **this : static_cast<T>(std::forward<U>(u));
2446 }
2447
2449 void reset() noexcept { m_value = nullptr; }
2450
2451private:
2452 T* m_value;
2453}; // namespace tl
2454
2455} // namespace tl
2456
2457namespace std {
2458// TODO SFINAE
2459template<class T>
2460struct hash<tl::optional<T>>
2461{
2462 ::std::size_t operator()(const tl::optional<T>& o) const
2463 {
2464 if (!o.has_value())
2465 return 0;
2466
2467 return std::hash<tl::detail::remove_const_t<T>>()(*o);
2468 }
2469};
2470} // namespace std
2471
2472#endif
const char * what() const noexcept
Used to represent an optional with no data; essentially a bool.
detail::invoke_result_t< U > map_or_else(F &&f, U &&u) const &&
constexpr optional(const optional< U > &rhs) noexcept
U map_or(F &&f, U &&u) const &
constexpr optional() noexcept
Constructs an optional that does not contain a value.
TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval< optional && >(), std::declval< F && >())) map(F &&f) &&
constexpr detail::invoke_result_t< F, const T & > and_then(F &&f) const &&
constexpr detail::invoke_result_t< F, const T & > and_then(F &&f) const &
~optional()=default
No-op.
constexpr optional disjunction(const optional &rhs) const &&
constexpr decltype(detail::optional_map_impl(std::declval< const optional && >(), std::declval< F && >())) transform(F &&f) const &&
optional< T > TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) &
Calls f if the optional is empty.
constexpr optional(nullopt_t) noexcept
constexpr decltype(detail::optional_map_impl(std::declval< const optional && >(), std::declval< F && >())) map(F &&f) const &&
constexpr decltype(detail::optional_map_impl(std::declval< const optional & >(), std::declval< F && >())) transform(F &&f) const &
TL_OPTIONAL_11_CONSTEXPR T & operator*() noexcept
Returns the stored value.
optional & operator=(const optional &rhs)=default
TL_OPTIONAL_11_CONSTEXPR T value_or(U &&u) &&noexcept
\group value_or
TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t< F, T & > and_then(F &&f) &
TL_OPTIONAL_11_CONSTEXPR optional(const optional &rhs) noexcept=default
TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval< optional & >(), std::declval< F && >())) transform(F &&f) &
Carries out some operation on the stored object if there is one.
constexpr optional disjunction(optional &&rhs) const &
TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) &&
U map_or(F &&f, U &&u) const &&
constexpr optional< typename std::decay< U >::type > conjunction(U &&u) const
Returns u if *this has a value, otherwise an empty optional.
TL_OPTIONAL_11_CONSTEXPR T * operator->() noexcept
optional< T > or_else(F &&f) const &
TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs)=default
optional & operator=(const optional< U > &rhs) noexcept
optional & operator=(nullopt_t) noexcept
constexpr decltype(detail::optional_map_impl(std::declval< const optional & >(), std::declval< F && >())) map(F &&f) const &
optional< T > TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const &
optional< T > or_else(F &&f) &&
TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval< optional && >(), std::declval< F && >())) transform(F &&f) &&
void reset() noexcept
Destroys the stored value if one exists, making the optional empty.
optional & operator=(U &&u)
Rebinds this optional to u.
TL_OPTIONAL_11_CONSTEXPR T & value()
TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) &
detail::invoke_result_t< U > map_or_else(F &&f, U &&u) &&
U map_or(F &&f, U &&u) &&
detail::invoke_result_t< U > map_or_else(F &&f, U &&u) const &
TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) &&
TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval< optional & >(), std::declval< F && >())) map(F &&f) &
Carries out some operation on the stored object if there is one.
constexpr optional(U &&u) noexcept
Constructs the stored value with u.
TL_OPTIONAL_11_CONSTEXPR const T & value() const
detail::invoke_result_t< U > map_or_else(F &&f, U &&u) &
TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) &
Returns rhs if *this is empty, otherwise the current value.
constexpr optional disjunction(optional &&rhs) const &&
constexpr bool has_value() const noexcept
constexpr T value_or(U &&u) const &noexcept
Returns the stored value if there is one, otherwise returns u
optional take()
Takes the value out of the optional, leaving it empty.
optional< T > TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) &&
U map_or(F &&f, U &&u) &
Maps the stored value with f if there is one, otherwise returns u
constexpr const T * operator->() const noexcept
Returns a pointer to the stored value.
constexpr const T & operator*() const noexcept
optional & emplace(U &&u) noexcept
Rebinds this optional to u.
void swap(optional &rhs) noexcept
constexpr optional disjunction(const optional &rhs) const &
TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t< F, T & > and_then(F &&f) &&
optional< T > or_else(F &&f) const &&
constexpr optional() noexcept=default
Constructs an optional that does not contain a value.
constexpr optional disjunction(const optional &rhs) const &
detail::invoke_result_t< U > map_or_else(F &&f, U &&u) const &&
constexpr decltype(optional_map_impl(std::declval< const optional & >(), std::declval< F && >())) map(F &&f) const &
TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) &&
TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t< F, T & > and_then(F &&f) &
TL_OPTIONAL_11_CONSTEXPR T && value() &&
TL_OPTIONAL_11_CONSTEXPR T & operator*() &
Returns the stored value.
TL_OPTIONAL_11_CONSTEXPR optional(const optional &rhs)=default
constexpr decltype(optional_map_impl(std::declval< const optional && >(), std::declval< F && >())) map(F &&f) const &&
TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) &
Returns rhs if *this is empty, otherwise the current value.
T & emplace(Args &&... args)
TL_OPTIONAL_11_CONSTEXPR const T && value() const &&
optional & operator=(optional &&rhs)=default
U map_or(F &&f, U &&u) const &
TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval< optional && >(), std::declval< F && >())) map(F &&f) &&
TL_OPTIONAL_11_CONSTEXPR T & value() &
optional(const optional< U > &rhs)
Converting copy constructor.
constexpr optional disjunction(optional &&rhs) const &
constexpr bool has_value() const noexcept
Returns whether or not the optional has a value.
TL_OPTIONAL_11_CONSTEXPR T * operator->()
constexpr optional(detail::enable_if_t< std::is_constructible< T, Args... >::value, in_place_t >, Args &&... args)
Constructs the stored value in-place using the given arguments.
optional & operator=(U &&u)
optional< T > or_else(F &&f) const &&
TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval< optional && >(), std::declval< F && >())) transform(F &&f) &&
constexpr const T * operator->() const
Returns a pointer to the stored value.
TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval< optional & >(), std::declval< F && >())) transform(F &&f) &
Carries out some operation on the stored object if there is one.
TL_OPTIONAL_11_CONSTEXPR optional(detail::enable_if_t< std::is_constructible< T, std::initializer_list< U > &, Args &&... >::value, in_place_t >, std::initializer_list< U > il, Args &&... args)
constexpr decltype(optional_map_impl(std::declval< const optional & >(), std::declval< F && >())) transform(F &&f) const &
TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs)=default
U map_or(F &&f, U &&u) const &&
void swap(optional &rhs) noexcept(std::is_nothrow_move_constructible< T >::value &&detail::is_nothrow_swappable< T >::value)
detail::invoke_result_t< U > map_or_else(F &&f, U &&u) const &
U map_or(F &&f, U &&u) &&
TL_OPTIONAL_11_CONSTEXPR T value_or(U &&u) &&
TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) &
~optional()=default
Destroys the stored value if there is one.
constexpr detail::invoke_result_t< F, const T && > and_then(F &&f) const &&
optional< T > or_else(F &&f) const &
detail::enable_if_t< std::is_constructible< T, std::initializer_list< U > &, Args &&... >::value, T & > emplace(std::initializer_list< U > il, Args &&... args)
constexpr const T & operator*() const &
TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t< F, T && > and_then(F &&f) &&
TL_OPTIONAL_11_CONSTEXPR const T & value() const &
constexpr optional disjunction(optional &&rhs) const &&
constexpr T value_or(U &&u) const &
Returns the stored value if there is one, otherwise returns u
detail::invoke_result_t< U > map_or_else(F &&f, U &&u) &
optional take()
Takes the value out of the optional, leaving it empty.
optional & operator=(optional< U > &&rhs)
constexpr optional(U &&u)
Constructs the stored value with u.
constexpr optional< typename std::decay< U >::type > conjunction(U &&u) const
Returns u if *this has a value, otherwise an empty optional.
optional & operator=(const optional< U > &rhs)
TL_OPTIONAL_11_CONSTEXPR T && operator*() &&
optional(optional< U > &&rhs)
Converting move constructor.
constexpr detail::invoke_result_t< F, const T & > and_then(F &&f) const &
void reset() noexcept
Destroys the stored value if one exists, making the optional empty.
constexpr const T && operator*() const &&
constexpr optional disjunction(const optional &rhs) const &&
U map_or(F &&f, U &&u) &
Maps the stored value with f if there is one, otherwise returns u.
optional & operator=(const optional &rhs)=default
TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval< optional & >(), std::declval< F && >())) map(F &&f) &
Carries out some operation on the stored object if there is one.
optional & operator=(nullopt_t) noexcept
optional< T > or_else(F &&f) &&
optional< T > TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) &&
detail::invoke_result_t< U > map_or_else(F &&f, U &&u) &&
TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) &&
optional< T > TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) &
Calls f if the optional is empty.
constexpr decltype(optional_map_impl(std::declval< const optional && >(), std::declval< F && >())) transform(F &&f) const &&
optional< T > TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const &
STL namespace.
std::false_type uses_std(...)
std::false_type can_swap(...) noexcept(false)
detail::enable_if_t< std::is_constructible< T, Other >::value && std::is_assignable< T &, Other >::value && !std::is_constructible< T, optional< U > & >::value && !std::is_constructible< T, optional< U > && >::value && !std::is_constructible< T, const optional< U > & >::value && !std::is_constructible< T, const optional< U > && >::value && !std::is_convertible< optional< U > &, T >::value && !std::is_convertible< optional< U > &&, T >::value && !std::is_convertible< const optional< U > &, T >::value && !std::is_convertible< const optional< U > &&, T >::value && !std::is_assignable< T &, optional< U > & >::value && !std::is_assignable< T &, optional< U > && >::value && !std::is_assignable< T &, const optional< U > & >::value && !std::is_assignable< T &, const optional< U > && >::value > enable_assign_from_other
enable_if_t<!returns_void< T &&, U... >::value > disable_if_ret_void
typename std::remove_reference< T >::type remove_reference_t
detail::enable_if_t< !std::is_same< optional< T >, detail::decay_t< U > >::value && !detail::conjunction< std::is_scalar< T >, std::is_same< T, detail::decay_t< U > > >::value && std::is_constructible< T, U >::value &&std::is_assignable< T &, U >::value > enable_assign_forward
typename std::enable_if< E, T >::type enable_if_t
typename std::decay< T >::type decay_t
detail::enable_if_t< std::is_constructible< T, U && >::value && !std::is_same< detail::decay_t< U >, in_place_t >::value && !std::is_same< optional< T >, detail::decay_t< U > >::value > enable_forward_value
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 auto optional_map_impl(Opt &&opt, F &&f) -> optional< Ret >
typename std::conditional< B, T, F >::type conditional_t
enable_if_t< returns_void< T &&, U... >::value > enable_if_ret_void
typename voider< Ts... >::type void_t
conditional_t< std::is_void< U >::value, monostate, U > fixup_void
typename invoke_result< F, Us... >::type invoke_result_t
detail::enable_if_t< std::is_constructible< T, Other >::value && !std::is_constructible< T, optional< U > & >::value && !std::is_constructible< T, optional< U > && >::value && !std::is_constructible< T, const optional< U > & >::value && !std::is_constructible< T, const optional< U > && >::value && !std::is_convertible< optional< U > &, T >::value && !std::is_convertible< optional< U > &&, T >::value && !std::is_convertible< const optional< U > &, T >::value && !std::is_convertible< const optional< U > &&, T >::value > enable_from_other
constexpr bool operator==(const optional< T > &lhs, const optional< U > &rhs)
Compares two optional objects.
static constexpr nullopt_t nullopt
Represents an empty optional.
constexpr bool operator!=(const optional< T > &lhs, const optional< U > &rhs)
constexpr bool operator>=(const optional< T > &lhs, const optional< U > &rhs)
constexpr bool operator<(const optional< T > &lhs, const optional< U > &rhs)
static constexpr in_place_t in_place
A tag to tell optional to construct its value in-place.
constexpr optional< Ret > make_optional(U &&v)
constexpr bool operator>(const optional< T > &lhs, const optional< U > &rhs)
constexpr bool operator<=(const optional< T > &lhs, const optional< U > &rhs)
void swap(optional< T > &lhs, optional< T > &rhs) noexcept(noexcept(lhs.swap(rhs)))
::std::size_t operator()(const tl::optional< T > &o) const
optional_copy_assign_base(const optional_copy_assign_base &rhs)=default
optional_copy_assign_base & operator=(const optional_copy_assign_base &rhs)
optional_copy_assign_base & operator=(optional_copy_assign_base &&rhs)=default
optional_copy_assign_base(optional_copy_assign_base &&rhs)=default
optional_copy_base & operator=(const optional_copy_base &rhs)=default
optional_copy_base(const optional_copy_base &rhs)
optional_copy_base & operator=(optional_copy_base &&rhs)=default
optional_copy_base(optional_copy_base &&rhs)=default
optional_delete_assign_base(const optional_delete_assign_base &)=default
optional_delete_assign_base(optional_delete_assign_base &&) noexcept=default
optional_delete_assign_base(optional_delete_assign_base &&) noexcept=default
optional_delete_assign_base(const optional_delete_assign_base &)=default
optional_delete_assign_base(const optional_delete_assign_base &)=default
optional_delete_assign_base(optional_delete_assign_base &&) noexcept=default
optional_delete_assign_base(optional_delete_assign_base &&) noexcept=default
optional_delete_assign_base(const optional_delete_assign_base &)=default
optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept=delete
optional_delete_ctor_base(const optional_delete_ctor_base &)=delete
optional_delete_ctor_base(const optional_delete_ctor_base &)=delete
optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept=default
optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept=delete
optional_delete_ctor_base(const optional_delete_ctor_base &)=default
optional_delete_ctor_base(const optional_delete_ctor_base &)=default
optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept=default
optional_move_assign_base & operator=(optional_move_assign_base &&rhs) noexcept(std::is_nothrow_move_constructible< T >::value &&std::is_nothrow_move_assignable< T >::value)
optional_move_assign_base(const optional_move_assign_base &rhs)=default
optional_move_assign_base & operator=(const optional_move_assign_base &rhs)=default
optional_move_assign_base(optional_move_assign_base &&rhs)=default
optional_move_base & operator=(const optional_move_base &rhs)=default
optional_move_base(const optional_move_base &rhs)=default
optional_move_base(optional_move_base &&rhs) noexcept(std::is_nothrow_move_constructible< T >::value)
optional_move_base & operator=(optional_move_base &&rhs)=default
constexpr const T && get() const &&
TL_OPTIONAL_11_CONSTEXPR T && get() &&
TL_OPTIONAL_11_CONSTEXPR T & get() &
TL_OPTIONAL_11_CONSTEXPR const T & get() const &
TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u)
TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept
TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u)
TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept
A tag type to tell optional to construct its value in-place.
in_place_t()=default
A tag type to represent an empty optional.
constexpr nullopt_t(do_not_use, do_not_use) noexcept
#define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T)
#define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T)
#define TL_OPTIONAL_11_CONSTEXPR
#define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)