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