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