libstdc++
experimental/optional
Go to the documentation of this file.
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 
45 namespace std _GLIBCXX_VISIBILITY(default)
46 {
47 _GLIBCXX_BEGIN_NAMESPACE_VERSION
48 
49 namespace experimental
50 {
51 inline 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