xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/include/experimental/optional (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1// <experimental/optional> -*- C++ -*-
2
3// Copyright (C) 2013-2022 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 <type_traits>
36#include <stdexcept>
37#include <new>
38#include <initializer_list>
39#include <bits/functexcept.h>
40#include <bits/functional_hash.h>
41#include <bits/enable_special_members.h>
42#include <bits/move.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
938