]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/include/std/optional
Implement LWG 2825, LWG 2756 breaks class template argument deduction for optional.
[thirdparty/gcc.git] / libstdc++-v3 / include / std / optional
1 // <optional> -*- C++ -*-
2
3 // Copyright (C) 2013-2017 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
24
25 /** @file include/optional
26 * This is a Standard C++ Library header.
27 */
28
29 #ifndef _GLIBCXX_OPTIONAL
30 #define _GLIBCXX_OPTIONAL 1
31
32 #if __cplusplus <= 201402L
33 # include <bits/c++17_warning.h>
34 #else
35
36 #include <utility>
37 #include <type_traits>
38 #include <stdexcept>
39 #include <new>
40 #include <initializer_list>
41 #include <bits/functexcept.h>
42 #include <bits/functional_hash.h>
43 #include <bits/enable_special_members.h>
44
45 namespace std _GLIBCXX_VISIBILITY(default)
46 {
47 _GLIBCXX_BEGIN_NAMESPACE_VERSION
48
49 /**
50 * @addtogroup utilities
51 * @{
52 */
53
54 template<typename _Tp>
55 class optional;
56
57 /// Tag type to disengage optional objects.
58 struct nullopt_t
59 {
60 // Do not user-declare default constructor at all for
61 // optional_value = {} syntax to work.
62 // nullopt_t() = delete;
63
64 // Used for constructing nullopt.
65 enum class _Construct { _Token };
66
67 // Must be constexpr for nullopt_t to be literal.
68 explicit constexpr nullopt_t(_Construct) { }
69 };
70
71 /// Tag to disengage optional objects.
72 constexpr nullopt_t nullopt { nullopt_t::_Construct::_Token };
73
74 /**
75 * @brief Exception class thrown when a disengaged optional object is
76 * dereferenced.
77 * @ingroup exceptions
78 */
79 class bad_optional_access : public logic_error
80 {
81 // XXX See LEWG 72, https://issues.isocpp.org/show_bug.cgi?id=72
82 public:
83 bad_optional_access() : logic_error("bad optional access") { }
84 // XXX This constructor is non-standard. Should not be inline
85 explicit bad_optional_access(const char* __arg) : logic_error(__arg) { }
86
87 virtual ~bad_optional_access() noexcept = default;
88 };
89
90 void
91 __throw_bad_optional_access(const char*)
92 __attribute__((__noreturn__));
93
94 // XXX Does not belong here.
95 inline void
96 __throw_bad_optional_access(const char* __s)
97 { _GLIBCXX_THROW_OR_ABORT(bad_optional_access(__s)); }
98
99 /**
100 * @brief Class template that holds the necessary state for @ref optional
101 * and that has the responsibility for construction and the special members.
102 *
103 * Such a separate base class template is necessary in order to
104 * conditionally enable the special members (e.g. copy/move constructors).
105 * Note that this means that @ref _Optional_base implements the
106 * functionality for copy and move assignment, but not for converting
107 * assignment.
108 *
109 * @see optional, _Enable_special_members
110 */
111 template<typename _Tp, bool _ShouldProvideDestructor =
112 !is_trivially_destructible<_Tp>::value>
113 class _Optional_base
114 {
115 private:
116 // Remove const to avoid prohibition of reusing object storage for
117 // const-qualified types in [3.8/9]. This is strictly internal
118 // and even optional itself is oblivious to it.
119 using _Stored_type = remove_const_t<_Tp>;
120
121 public:
122
123 // Constructors for disengaged optionals.
124 constexpr _Optional_base() noexcept
125 : _M_empty{} { }
126
127 constexpr _Optional_base(nullopt_t) noexcept
128 : _Optional_base{} { }
129
130 // Constructors for engaged optionals.
131 template<typename... _Args,
132 enable_if_t<is_constructible_v<_Tp, _Args&&...>, bool> = false>
133 constexpr explicit _Optional_base(in_place_t, _Args&&... __args)
134 : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true) { }
135
136 template<typename _Up, typename... _Args,
137 enable_if_t<is_constructible_v<_Tp,
138 initializer_list<_Up>&,
139 _Args&&...>, bool> = false>
140 constexpr explicit _Optional_base(in_place_t,
141 initializer_list<_Up> __il,
142 _Args&&... __args)
143 : _M_payload(__il, std::forward<_Args>(__args)...),
144 _M_engaged(true) { }
145
146 // Copy and move constructors.
147 _Optional_base(const _Optional_base& __other)
148 {
149 if (__other._M_engaged)
150 this->_M_construct(__other._M_get());
151 }
152
153 _Optional_base(_Optional_base&& __other)
154 noexcept(is_nothrow_move_constructible<_Tp>())
155 {
156 if (__other._M_engaged)
157 this->_M_construct(std::move(__other._M_get()));
158 }
159
160 // Assignment operators.
161 _Optional_base&
162 operator=(const _Optional_base& __other)
163 {
164 if (this->_M_engaged && __other._M_engaged)
165 this->_M_get() = __other._M_get();
166 else
167 {
168 if (__other._M_engaged)
169 this->_M_construct(__other._M_get());
170 else
171 this->_M_reset();
172 }
173
174 return *this;
175 }
176
177 _Optional_base&
178 operator=(_Optional_base&& __other)
179 noexcept(__and_<is_nothrow_move_constructible<_Tp>,
180 is_nothrow_move_assignable<_Tp>>())
181 {
182 if (this->_M_engaged && __other._M_engaged)
183 this->_M_get() = std::move(__other._M_get());
184 else
185 {
186 if (__other._M_engaged)
187 this->_M_construct(std::move(__other._M_get()));
188 else
189 this->_M_reset();
190 }
191 return *this;
192 }
193
194 // Destructor.
195 ~_Optional_base()
196 {
197 if (this->_M_engaged)
198 this->_M_payload.~_Stored_type();
199 }
200
201 // The following functionality is also needed by optional, hence the
202 // protected accessibility.
203 protected:
204 constexpr bool _M_is_engaged() const noexcept
205 { return this->_M_engaged; }
206
207 // The _M_get operations have _M_engaged as a precondition.
208 constexpr _Tp&
209 _M_get() noexcept
210 { return _M_payload; }
211
212 constexpr const _Tp&
213 _M_get() const noexcept
214 { return _M_payload; }
215
216 // The _M_construct operation has !_M_engaged as a precondition
217 // while _M_destruct has _M_engaged as a precondition.
218 template<typename... _Args>
219 void
220 _M_construct(_Args&&... __args)
221 noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
222 {
223 ::new (std::__addressof(this->_M_payload))
224 _Stored_type(std::forward<_Args>(__args)...);
225 this->_M_engaged = true;
226 }
227
228 void
229 _M_destruct()
230 {
231 this->_M_engaged = false;
232 this->_M_payload.~_Stored_type();
233 }
234
235 // _M_reset is a 'safe' operation with no precondition.
236 void
237 _M_reset()
238 {
239 if (this->_M_engaged)
240 this->_M_destruct();
241 }
242
243 private:
244 struct _Empty_byte { };
245 union {
246 _Empty_byte _M_empty;
247 _Stored_type _M_payload;
248 };
249 bool _M_engaged = false;
250 };
251
252 /// Partial specialization that is exactly identical to the primary template
253 /// save for not providing a destructor, to fulfill triviality requirements.
254 template<typename _Tp>
255 class _Optional_base<_Tp, false>
256 {
257 private:
258 using _Stored_type = remove_const_t<_Tp>;
259
260 public:
261 constexpr _Optional_base() noexcept
262 : _M_empty{} { }
263
264 constexpr _Optional_base(nullopt_t) noexcept
265 : _Optional_base{} { }
266
267 template<typename... _Args,
268 enable_if_t<is_constructible_v<_Tp, _Args&&...>, bool> = false>
269 constexpr explicit _Optional_base(in_place_t, _Args&&... __args)
270 : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true) { }
271
272 template<typename _Up, typename... _Args,
273 enable_if_t<is_constructible_v<_Tp,
274 initializer_list<_Up>&,
275 _Args&&...>, bool> = false>
276 constexpr explicit _Optional_base(in_place_t,
277 initializer_list<_Up> __il,
278 _Args&&... __args)
279 : _M_payload(__il, std::forward<_Args>(__args)...),
280 _M_engaged(true) { }
281
282 _Optional_base(const _Optional_base& __other)
283 {
284 if (__other._M_engaged)
285 this->_M_construct(__other._M_get());
286 }
287
288 _Optional_base(_Optional_base&& __other)
289 noexcept(is_nothrow_move_constructible<_Tp>())
290 {
291 if (__other._M_engaged)
292 this->_M_construct(std::move(__other._M_get()));
293 }
294
295 _Optional_base&
296 operator=(const _Optional_base& __other)
297 {
298 if (this->_M_engaged && __other._M_engaged)
299 this->_M_get() = __other._M_get();
300 else
301 {
302 if (__other._M_engaged)
303 this->_M_construct(__other._M_get());
304 else
305 this->_M_reset();
306 }
307 return *this;
308 }
309
310 _Optional_base&
311 operator=(_Optional_base&& __other)
312 noexcept(__and_<is_nothrow_move_constructible<_Tp>,
313 is_nothrow_move_assignable<_Tp>>())
314 {
315 if (this->_M_engaged && __other._M_engaged)
316 this->_M_get() = std::move(__other._M_get());
317 else
318 {
319 if (__other._M_engaged)
320 this->_M_construct(std::move(__other._M_get()));
321 else
322 this->_M_reset();
323 }
324 return *this;
325 }
326
327 // Sole difference
328 // ~_Optional_base() noexcept = default;
329
330 protected:
331 constexpr bool _M_is_engaged() const noexcept
332 { return this->_M_engaged; }
333
334 constexpr _Tp&
335 _M_get() noexcept
336 { return _M_payload; }
337
338 constexpr const _Tp&
339 _M_get() const noexcept
340 { return _M_payload; }
341
342 template<typename... _Args>
343 void
344 _M_construct(_Args&&... __args)
345 noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
346 {
347 ::new (std::__addressof(this->_M_payload))
348 _Stored_type(std::forward<_Args>(__args)...);
349 this->_M_engaged = true;
350 }
351
352 void
353 _M_destruct()
354 {
355 this->_M_engaged = false;
356 this->_M_payload.~_Stored_type();
357 }
358
359 void
360 _M_reset()
361 {
362 if (this->_M_engaged)
363 this->_M_destruct();
364 }
365
366 private:
367 struct _Empty_byte { };
368 union
369 {
370 _Empty_byte _M_empty;
371 _Stored_type _M_payload;
372 };
373 bool _M_engaged = false;
374 };
375
376 template<typename _Tp>
377 class optional;
378
379 template<typename _Tp, typename _Up>
380 using __converts_from_optional =
381 __or_<is_constructible<_Tp, const optional<_Up>&>,
382 is_constructible<_Tp, optional<_Up>&>,
383 is_constructible<_Tp, const optional<_Up>&&>,
384 is_constructible<_Tp, optional<_Up>&&>,
385 is_convertible<const optional<_Up>&, _Tp>,
386 is_convertible<optional<_Up>&, _Tp>,
387 is_convertible<const optional<_Up>&&, _Tp>,
388 is_convertible<optional<_Up>&&, _Tp>>;
389
390 template<typename _Tp, typename _Up>
391 using __assigns_from_optional =
392 __or_<is_assignable<_Tp&, const optional<_Up>&>,
393 is_assignable<_Tp&, optional<_Up>&>,
394 is_assignable<_Tp&, const optional<_Up>&&>,
395 is_assignable<_Tp&, optional<_Up>&&>>;
396
397 /**
398 * @brief Class template for optional values.
399 */
400 template<typename _Tp>
401 class optional
402 : private _Optional_base<_Tp>,
403 private _Enable_copy_move<
404 // Copy constructor.
405 is_copy_constructible<_Tp>::value,
406 // Copy assignment.
407 __and_<is_copy_constructible<_Tp>, is_copy_assignable<_Tp>>::value,
408 // Move constructor.
409 is_move_constructible<_Tp>::value,
410 // Move assignment.
411 __and_<is_move_constructible<_Tp>, is_move_assignable<_Tp>>::value,
412 // Unique tag type.
413 optional<_Tp>>
414 {
415 static_assert(__and_<__not_<is_same<remove_cv_t<_Tp>, nullopt_t>>,
416 __not_<is_same<remove_cv_t<_Tp>, in_place_t>>,
417 __not_<is_reference<_Tp>>>(),
418 "Invalid instantiation of optional<T>");
419
420 private:
421 using _Base = _Optional_base<_Tp>;
422
423 public:
424 using value_type = _Tp;
425
426 constexpr optional() = default;
427
428 constexpr optional(nullopt_t) noexcept
429 : _Base(nullopt) { }
430
431 // Converting constructors for engaged optionals.
432 template <typename _Up = _Tp,
433 enable_if_t<__and_<
434 __not_<is_same<optional<_Tp>, decay_t<_Up>>>,
435 __not_<is_same<in_place_t, decay_t<_Up>>>,
436 is_constructible<_Tp, _Up&&>,
437 is_convertible<_Up&&, _Tp>
438 >::value, bool> = true>
439 constexpr optional(_Up&& __t)
440 : _Base(std::in_place, std::forward<_Up>(__t)) { }
441
442 template <typename _Up = _Tp,
443 enable_if_t<__and_<
444 __not_<is_same<optional<_Tp>, decay_t<_Up>>>,
445 __not_<is_same<in_place_t, decay_t<_Up>>>,
446 is_constructible<_Tp, _Up&&>,
447 __not_<is_convertible<_Up&&, _Tp>>
448 >::value, bool> = false>
449 explicit constexpr optional(_Up&& __t)
450 : _Base(std::in_place, std::forward<_Up>(__t)) { }
451
452 template <typename _Up,
453 enable_if_t<__and_<
454 __not_<is_same<_Tp, _Up>>,
455 is_constructible<_Tp, const _Up&>,
456 is_convertible<const _Up&, _Tp>,
457 __not_<__converts_from_optional<_Tp, _Up>>
458 >::value, bool> = true>
459 constexpr optional(const optional<_Up>& __t)
460 {
461 if (__t)
462 emplace(*__t);
463 }
464
465 template <typename _Up,
466 enable_if_t<__and_<
467 __not_<is_same<_Tp, _Up>>,
468 is_constructible<_Tp, const _Up&>,
469 __not_<is_convertible<const _Up&, _Tp>>,
470 __not_<__converts_from_optional<_Tp, _Up>>
471 >::value, bool> = false>
472 explicit constexpr optional(const optional<_Up>& __t)
473 {
474 if (__t)
475 emplace(*__t);
476 }
477
478 template <typename _Up,
479 enable_if_t<__and_<
480 __not_<is_same<_Tp, _Up>>,
481 is_constructible<_Tp, _Up&&>,
482 is_convertible<_Up&&, _Tp>,
483 __not_<__converts_from_optional<_Tp, _Up>>
484 >::value, bool> = true>
485 constexpr optional(optional<_Up>&& __t)
486 {
487 if (__t)
488 emplace(std::move(*__t));
489 }
490
491 template <typename _Up,
492 enable_if_t<__and_<
493 __not_<is_same<_Tp, _Up>>,
494 is_constructible<_Tp, _Up&&>,
495 __not_<is_convertible<_Up&&, _Tp>>,
496 __not_<__converts_from_optional<_Tp, _Up>>
497 >::value, bool> = false>
498 explicit constexpr optional(optional<_Up>&& __t)
499 {
500 if (__t)
501 emplace(std::move(*__t));
502 }
503
504 template<typename... _Args,
505 enable_if_t<is_constructible_v<_Tp, _Args&&...>, bool> = false>
506 explicit constexpr optional(in_place_t, _Args&&... __args)
507 : _Base(std::in_place, std::forward<_Args>(__args)...) { }
508
509 template<typename _Up, typename... _Args,
510 enable_if_t<is_constructible_v<_Tp,
511 initializer_list<_Up>&,
512 _Args&&...>, bool> = false>
513 explicit constexpr optional(in_place_t,
514 initializer_list<_Up> __il,
515 _Args&&... __args)
516 : _Base(std::in_place, __il, std::forward<_Args>(__args)...) { }
517
518 // Assignment operators.
519 optional&
520 operator=(nullopt_t) noexcept
521 {
522 this->_M_reset();
523 return *this;
524 }
525
526 template<typename _Up = _Tp>
527 enable_if_t<__and_<
528 __not_<is_same<optional<_Tp>, decay_t<_Up>>>,
529 is_constructible<_Tp, _Up>,
530 __not_<__and_<is_scalar<_Tp>,
531 is_same<_Tp, decay_t<_Up>>>>,
532 is_assignable<_Tp&, _Up>>::value,
533 optional&>
534 operator=(_Up&& __u)
535 {
536 if (this->_M_is_engaged())
537 this->_M_get() = std::forward<_Up>(__u);
538 else
539 this->_M_construct(std::forward<_Up>(__u));
540
541 return *this;
542 }
543
544 template<typename _Up>
545 enable_if_t<__and_<
546 __not_<is_same<_Tp, _Up>>,
547 is_constructible<_Tp, const _Up&>,
548 is_assignable<_Tp&, _Up>,
549 __not_<__converts_from_optional<_Tp, _Up>>,
550 __not_<__assigns_from_optional<_Tp, _Up>>
551 >::value,
552 optional&>
553 operator=(const optional<_Up>& __u)
554 {
555 if (__u)
556 {
557 if (this->_M_is_engaged())
558 this->_M_get() = *__u;
559 else
560 this->_M_construct(*__u);
561 }
562 else
563 {
564 this->_M_reset();
565 }
566 return *this;
567 }
568
569 template<typename _Up>
570 enable_if_t<__and_<
571 __not_<is_same<_Tp, _Up>>,
572 is_constructible<_Tp, _Up>,
573 is_assignable<_Tp&, _Up>,
574 __not_<__converts_from_optional<_Tp, _Up>>,
575 __not_<__assigns_from_optional<_Tp, _Up>>
576 >::value,
577 optional&>
578 operator=(optional<_Up>&& __u)
579 {
580 if (__u)
581 {
582 if (this->_M_is_engaged())
583 this->_M_get() = std::move(*__u);
584 else
585 this->_M_construct(std::move(*__u));
586 }
587 else
588 {
589 this->_M_reset();
590 }
591
592 return *this;
593 }
594
595 template<typename... _Args>
596 enable_if_t<is_constructible<_Tp, _Args&&...>::value>
597 emplace(_Args&&... __args)
598 {
599 this->_M_reset();
600 this->_M_construct(std::forward<_Args>(__args)...);
601 }
602
603 template<typename _Up, typename... _Args>
604 enable_if_t<is_constructible<_Tp, initializer_list<_Up>&,
605 _Args&&...>::value>
606 emplace(initializer_list<_Up> __il, _Args&&... __args)
607 {
608 this->_M_reset();
609 this->_M_construct(__il, std::forward<_Args>(__args)...);
610 }
611
612 // Destructor is implicit, implemented in _Optional_base.
613
614 // Swap.
615 void
616 swap(optional& __other)
617 noexcept(is_nothrow_move_constructible<_Tp>()
618 && is_nothrow_swappable_v<_Tp>)
619 {
620 using std::swap;
621
622 if (this->_M_is_engaged() && __other._M_is_engaged())
623 swap(this->_M_get(), __other._M_get());
624 else if (this->_M_is_engaged())
625 {
626 __other._M_construct(std::move(this->_M_get()));
627 this->_M_destruct();
628 }
629 else if (__other._M_is_engaged())
630 {
631 this->_M_construct(std::move(__other._M_get()));
632 __other._M_destruct();
633 }
634 }
635
636 // Observers.
637 constexpr const _Tp*
638 operator->() const
639 { return std::__addressof(this->_M_get()); }
640
641 _Tp*
642 operator->()
643 { return std::__addressof(this->_M_get()); }
644
645 constexpr const _Tp&
646 operator*() const&
647 { return this->_M_get(); }
648
649 constexpr _Tp&
650 operator*()&
651 { return this->_M_get(); }
652
653 constexpr _Tp&&
654 operator*()&&
655 { return std::move(this->_M_get()); }
656
657 constexpr const _Tp&&
658 operator*() const&&
659 { return std::move(this->_M_get()); }
660
661 constexpr explicit operator bool() const noexcept
662 { return this->_M_is_engaged(); }
663
664 constexpr bool has_value() const noexcept
665 { return this->_M_is_engaged(); }
666
667 constexpr const _Tp&
668 value() const&
669 {
670 return this->_M_is_engaged()
671 ? this->_M_get()
672 : (__throw_bad_optional_access("Attempt to access value of a "
673 "disengaged optional object"),
674 this->_M_get());
675 }
676
677 constexpr _Tp&
678 value()&
679 {
680 return this->_M_is_engaged()
681 ? this->_M_get()
682 : (__throw_bad_optional_access("Attempt to access value of a "
683 "disengaged optional object"),
684 this->_M_get());
685 }
686
687 constexpr _Tp&&
688 value()&&
689 {
690 return this->_M_is_engaged()
691 ? std::move(this->_M_get())
692 : (__throw_bad_optional_access("Attempt to access value of a "
693 "disengaged optional object"),
694 std::move(this->_M_get()));
695 }
696
697 constexpr const _Tp&&
698 value() const&&
699 {
700 return this->_M_is_engaged()
701 ? std::move(this->_M_get())
702 : (__throw_bad_optional_access("Attempt to access value of a "
703 "disengaged optional object"),
704 std::move(this->_M_get()));
705 }
706
707 template<typename _Up>
708 constexpr _Tp
709 value_or(_Up&& __u) const&
710 {
711 static_assert(__and_<is_copy_constructible<_Tp>,
712 is_convertible<_Up&&, _Tp>>(),
713 "Cannot return value");
714
715 return this->_M_is_engaged()
716 ? this->_M_get()
717 : static_cast<_Tp>(std::forward<_Up>(__u));
718 }
719
720 template<typename _Up>
721 _Tp
722 value_or(_Up&& __u) &&
723 {
724 static_assert(__and_<is_move_constructible<_Tp>,
725 is_convertible<_Up&&, _Tp>>(),
726 "Cannot return value" );
727
728 return this->_M_is_engaged()
729 ? std::move(this->_M_get())
730 : static_cast<_Tp>(std::forward<_Up>(__u));
731 }
732 void reset() noexcept { this->_M_reset(); }
733 };
734
735 template<typename _Tp>
736 using __optional_relop_t =
737 enable_if_t<is_convertible<_Tp, bool>::value, bool>;
738
739 // Comparisons between optional values.
740 template<typename _Tp>
741 constexpr auto
742 operator==(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
743 -> __optional_relop_t<decltype(declval<_Tp>() == declval<_Tp>())>
744 {
745 return static_cast<bool>(__lhs) == static_cast<bool>(__rhs)
746 && (!__lhs || *__lhs == *__rhs);
747 }
748
749 template<typename _Tp>
750 constexpr auto
751 operator!=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
752 -> __optional_relop_t<decltype(declval<_Tp>() != declval<_Tp>())>
753 {
754 return static_cast<bool>(__lhs) != static_cast<bool>(__rhs)
755 || (static_cast<bool>(__lhs) && *__lhs != *__rhs);
756 }
757
758 template<typename _Tp>
759 constexpr auto
760 operator<(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
761 -> __optional_relop_t<decltype(declval<_Tp>() < declval<_Tp>())>
762 {
763 return static_cast<bool>(__rhs) && (!__lhs || *__lhs < *__rhs);
764 }
765
766 template<typename _Tp>
767 constexpr auto
768 operator>(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
769 -> __optional_relop_t<decltype(declval<_Tp>() > declval<_Tp>())>
770 {
771 return static_cast<bool>(__lhs) && (!__rhs || *__lhs > *__rhs);
772 }
773
774 template<typename _Tp>
775 constexpr auto
776 operator<=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
777 -> __optional_relop_t<decltype(declval<_Tp>() <= declval<_Tp>())>
778 {
779 return !__lhs || (static_cast<bool>(__rhs) && *__lhs <= *__rhs);
780 }
781
782 template<typename _Tp>
783 constexpr auto
784 operator>=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
785 -> __optional_relop_t<decltype(declval<_Tp>() >= declval<_Tp>())>
786 {
787 return !__rhs || (static_cast<bool>(__lhs) && *__lhs >= *__rhs);
788 }
789
790 // Comparisons with nullopt.
791 template<typename _Tp>
792 constexpr bool
793 operator==(const optional<_Tp>& __lhs, nullopt_t) noexcept
794 { return !__lhs; }
795
796 template<typename _Tp>
797 constexpr bool
798 operator==(nullopt_t, const optional<_Tp>& __rhs) noexcept
799 { return !__rhs; }
800
801 template<typename _Tp>
802 constexpr bool
803 operator!=(const optional<_Tp>& __lhs, nullopt_t) noexcept
804 { return static_cast<bool>(__lhs); }
805
806 template<typename _Tp>
807 constexpr bool
808 operator!=(nullopt_t, const optional<_Tp>& __rhs) noexcept
809 { return static_cast<bool>(__rhs); }
810
811 template<typename _Tp>
812 constexpr bool
813 operator<(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept
814 { return false; }
815
816 template<typename _Tp>
817 constexpr bool
818 operator<(nullopt_t, const optional<_Tp>& __rhs) noexcept
819 { return static_cast<bool>(__rhs); }
820
821 template<typename _Tp>
822 constexpr bool
823 operator>(const optional<_Tp>& __lhs, nullopt_t) noexcept
824 { return static_cast<bool>(__lhs); }
825
826 template<typename _Tp>
827 constexpr bool
828 operator>(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept
829 { return false; }
830
831 template<typename _Tp>
832 constexpr bool
833 operator<=(const optional<_Tp>& __lhs, nullopt_t) noexcept
834 { return !__lhs; }
835
836 template<typename _Tp>
837 constexpr bool
838 operator<=(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept
839 { return true; }
840
841 template<typename _Tp>
842 constexpr bool
843 operator>=(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept
844 { return true; }
845
846 template<typename _Tp>
847 constexpr bool
848 operator>=(nullopt_t, const optional<_Tp>& __rhs) noexcept
849 { return !__rhs; }
850
851 // Comparisons with value type.
852 template<typename _Tp>
853 constexpr auto
854 operator==(const optional<_Tp>& __lhs, const _Tp& __rhs)
855 -> __optional_relop_t<decltype(declval<_Tp>() == declval<_Tp>())>
856 { return __lhs && *__lhs == __rhs; }
857
858 template<typename _Tp>
859 constexpr auto
860 operator==(const _Tp& __lhs, const optional<_Tp>& __rhs)
861 -> __optional_relop_t<decltype(declval<_Tp>() == declval<_Tp>())>
862 { return __rhs && __lhs == *__rhs; }
863
864 template<typename _Tp>
865 constexpr auto
866 operator!=(const optional<_Tp>& __lhs, const _Tp& __rhs)
867 -> __optional_relop_t<decltype(declval<_Tp>() != declval<_Tp>())>
868 { return !__lhs || *__lhs != __rhs; }
869
870 template<typename _Tp>
871 constexpr auto
872 operator!=(const _Tp& __lhs, const optional<_Tp>& __rhs)
873 -> __optional_relop_t<decltype(declval<_Tp>() != declval<_Tp>())>
874 { return !__rhs || __lhs != *__rhs; }
875
876 template<typename _Tp>
877 constexpr auto
878 operator<(const optional<_Tp>& __lhs, const _Tp& __rhs)
879 -> __optional_relop_t<decltype(declval<_Tp>() < declval<_Tp>())>
880 { return !__lhs || *__lhs < __rhs; }
881
882 template<typename _Tp>
883 constexpr auto
884 operator<(const _Tp& __lhs, const optional<_Tp>& __rhs)
885 -> __optional_relop_t<decltype(declval<_Tp>() < declval<_Tp>())>
886 { return __rhs && __lhs < *__rhs; }
887
888 template<typename _Tp>
889 constexpr auto
890 operator>(const optional<_Tp>& __lhs, const _Tp& __rhs)
891 -> __optional_relop_t<decltype(declval<_Tp>() > declval<_Tp>())>
892 { return __lhs && *__lhs > __rhs; }
893
894 template<typename _Tp>
895 constexpr auto
896 operator>(const _Tp& __lhs, const optional<_Tp>& __rhs)
897 -> __optional_relop_t<decltype(declval<_Tp>() > declval<_Tp>())>
898 { return !__rhs || __lhs > *__rhs; }
899
900 template<typename _Tp>
901 constexpr auto
902 operator<=(const optional<_Tp>& __lhs, const _Tp& __rhs)
903 -> __optional_relop_t<decltype(declval<_Tp>() <= declval<_Tp>())>
904 { return !__lhs || *__lhs <= __rhs; }
905
906 template<typename _Tp>
907 constexpr auto
908 operator<=(const _Tp& __lhs, const optional<_Tp>& __rhs)
909 -> __optional_relop_t<decltype(declval<_Tp>() <= declval<_Tp>())>
910 { return __rhs && __lhs <= *__rhs; }
911
912 template<typename _Tp>
913 constexpr auto
914 operator>=(const optional<_Tp>& __lhs, const _Tp& __rhs)
915 -> __optional_relop_t<decltype(declval<_Tp>() >= declval<_Tp>())>
916 { return __lhs && *__lhs >= __rhs; }
917
918 template<typename _Tp>
919 constexpr auto
920 operator>=(const _Tp& __lhs, const optional<_Tp>& __rhs)
921 -> __optional_relop_t<decltype(declval<_Tp>() >= declval<_Tp>())>
922 { return !__rhs || __lhs >= *__rhs; }
923
924 // Swap and creation functions.
925
926 // _GLIBCXX_RESOLVE_LIB_DEFECTS
927 // 2748. swappable traits for optionals
928 template<typename _Tp>
929 inline enable_if_t<is_move_constructible_v<_Tp> && is_swappable_v<_Tp>>
930 swap(optional<_Tp>& __lhs, optional<_Tp>& __rhs)
931 noexcept(noexcept(__lhs.swap(__rhs)))
932 { __lhs.swap(__rhs); }
933
934 template<typename _Tp>
935 enable_if_t<!(is_move_constructible_v<_Tp> && is_swappable_v<_Tp>)>
936 swap(optional<_Tp>&, optional<_Tp>&) = delete;
937
938 template<typename _Tp>
939 constexpr optional<decay_t<_Tp>>
940 make_optional(_Tp&& __t)
941 { return optional<decay_t<_Tp>> { std::forward<_Tp>(__t) }; }
942
943 template<typename _Tp, typename ..._Args>
944 constexpr optional<_Tp>
945 make_optional(_Args&&... __args)
946 { return optional<_Tp> { in_place, std::forward<_Args>(__args)... }; }
947
948 template<typename _Tp, typename _Up, typename ..._Args>
949 constexpr optional<_Tp>
950 make_optional(initializer_list<_Up> __il, _Args&&... __args)
951 { return optional<_Tp> { in_place, __il, std::forward<_Args>(__args)... }; }
952
953 // Hash.
954
955 template<typename _Tp, bool
956 = __poison_hash<remove_const_t<_Tp>>::__enable_hash_call>
957 struct __optional_hash_call_base
958 {
959 size_t
960 operator()(const optional<_Tp>& __t) const
961 noexcept(noexcept(hash<_Tp> {}(*__t)))
962 {
963 // We pick an arbitrary hash for disengaged optionals which hopefully
964 // usual values of _Tp won't typically hash to.
965 constexpr size_t __magic_disengaged_hash = static_cast<size_t>(-3333);
966 return __t ? hash<_Tp> {}(*__t) : __magic_disengaged_hash;
967 }
968 };
969
970 template<typename _Tp>
971 struct __optional_hash_call_base<_Tp, false> {};
972
973 template<typename _Tp>
974 struct hash<optional<_Tp>>
975 : private __poison_hash<remove_const_t<_Tp>>,
976 public __optional_hash_call_base<_Tp>
977 {
978 using result_type = size_t;
979 using argument_type = optional<_Tp>;
980 };
981
982 /// @}
983
984 template <typename _Tp> optional(_Tp) -> optional<_Tp>;
985
986 _GLIBCXX_END_NAMESPACE_VERSION
987 } // namespace std
988
989 #endif // C++17
990
991 #endif // _GLIBCXX_OPTIONAL