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