Horizon
optional.hpp
Go to the documentation of this file.
1 // Range v3 library
3 //
4 // Copyright Casey Carter 2017
5 //
6 // Use, modification and distribution is subject to the
7 // Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 //
11 // Project home: https://github.com/ericniebler/range-v3
12 //
13 
14 #ifndef RANGES_V3_UTILITY_OPTIONAL_HPP
15 #define RANGES_V3_UTILITY_OPTIONAL_HPP
16 
17 #include <exception>
18 #include <initializer_list>
19 #include <memory>
20 #include <new>
21 
22 #include <concepts/concepts.hpp>
23 
24 #include <range/v3/detail/config.hpp>
25 #include <range/v3/utility/addressof.hpp>
27 #include <range/v3/utility/static_const.hpp>
29 
30 #include <range/v3/detail/prologue.hpp>
31 
32 namespace ranges
33 {
34  template<typename>
35  struct optional;
36 
37  struct bad_optional_access : std::exception
38  {
39  virtual const char * what() const noexcept override
40  {
41  return "bad optional access";
42  }
43  };
44 
45  struct nullopt_t
46  {
47  struct tag
48  {};
49  constexpr explicit nullopt_t(tag) noexcept
50  {}
51  };
52 #if RANGES_CXX_INLINE_VARIABLES >= RANGES_CXX_INLINE_VARIABLES_17
53  inline constexpr nullopt_t nullopt{nullopt_t::tag{}};
54 #else
56  namespace detail
57  {
58  template<typename>
59  struct nullopt_holder
60  {
61  static constexpr nullopt_t nullopt{nullopt_t::tag{}};
62  };
63  template<typename T>
64  constexpr nullopt_t nullopt_holder<T>::nullopt;
65  } // namespace detail
67  namespace
68  {
69  constexpr auto & nullopt = detail::nullopt_holder<void>::nullopt;
70  }
71 #endif
72 
74  namespace detail
75  {
76  template<typename = void>
77  [[noreturn]] bool throw_bad_optional_access()
78  {
79  throw bad_optional_access{};
80  }
81 
82  namespace optional_adl
83  {
84  template<typename T, bool = std::is_trivially_destructible<T>::value>
85  struct optional_storage
86  {
87  union
88  {
89  char dummy_;
91  };
92  bool engaged_;
93 
94  constexpr optional_storage() noexcept
95  : optional_storage(
96  tag{},
98  detail::is_trivially_copyable_v<T>>{})
99  {}
100  template(typename... Args)(
101  requires constructible_from<T, Args...>)
102  constexpr explicit optional_storage(in_place_t,
103  Args &&... args) //
104  noexcept(std::is_nothrow_constructible<T, Args...>::value)
105  : data_(static_cast<Args &&>(args)...)
106  , engaged_{true}
107  {}
108 
109  constexpr void reset() noexcept
110  {
111  engaged_ = false;
112  }
113 
114  private:
115  struct tag
116  {};
117  constexpr optional_storage(tag, std::false_type) noexcept
118  : dummy_{}
119  , engaged_{false}
120  {}
121  constexpr optional_storage(tag, std::true_type) noexcept
122  : data_{}
123  , engaged_{false}
124  {}
125  };
126 
127  template<typename T>
128  struct optional_storage<T, false>
129  {
130  union
131  {
132  char dummy_;
134  };
135  bool engaged_;
136 
137  ~optional_storage()
138  {
139  reset();
140  }
141  constexpr optional_storage() noexcept
142  : dummy_{}
143  , engaged_{false}
144  {}
145  template(typename... Args)(
146  requires constructible_from<T, Args...>)
147  constexpr explicit optional_storage(in_place_t,
148  Args &&... args) //
149  noexcept(std::is_nothrow_constructible<T, Args...>::value)
150  : data_(static_cast<Args &&>(args)...)
151  , engaged_{true}
152  {}
153  optional_storage(optional_storage const &) = default;
154  optional_storage(optional_storage &&) = default;
155  optional_storage & operator=(optional_storage const &) = default;
156  optional_storage & operator=(optional_storage &&) = default;
157 
158  void reset() noexcept
159  {
160  if(engaged_)
161  {
162  data_.~T();
163  engaged_ = false;
164  }
165  }
166  };
167 
168  template<typename T>
169  struct optional_base : private optional_storage<T>
170  {
171  using optional_storage<T>::optional_storage;
172  using optional_storage<T>::reset;
173 
174  constexpr bool has_value() const noexcept
175  {
176  return engaged_;
177  }
178  constexpr T & operator*() & noexcept
179  {
180  return RANGES_EXPECT(engaged_), data_;
181  }
182  constexpr T const & operator*() const & noexcept
183  {
184  return RANGES_EXPECT(engaged_), data_;
185  }
186  constexpr T && operator*() && noexcept
187  {
188  return RANGES_EXPECT(engaged_), detail::move(data_);
189  }
190  constexpr T const && operator*() const && noexcept
191  {
192  return RANGES_EXPECT(engaged_), detail::move(data_);
193  }
194  constexpr T * operator->() noexcept
195  {
196  return RANGES_EXPECT(engaged_), detail::addressof(data_);
197  }
198  constexpr T const * operator->() const noexcept
199  {
200  return RANGES_EXPECT(engaged_), detail::addressof(data_);
201  }
202  CPP_member
203  constexpr auto swap(optional_base & that) //
204  noexcept(std::is_nothrow_move_constructible<T>::value &&
205  is_nothrow_swappable<T>::value) //
206  -> CPP_ret(void)(
207  requires move_constructible<T> && swappable<T>)
208  {
209  constexpr bool can_swap_trivially =
210  !::concepts::adl_swap_detail::is_adl_swappable_v<T> &&
211  detail::is_trivially_move_constructible_v<T> &&
212  detail::is_trivially_move_assignable_v<T>;
213 
214  swap_(meta::bool_<can_swap_trivially>{}, that);
215  }
216 
217  protected:
218  template(typename... Args)(
219  requires constructible_from<T, Args...>)
220  T & construct_from(Args &&... args)
221  noexcept(std::is_nothrow_constructible<T, Args...>::value)
222  {
223  RANGES_EXPECT(!engaged_);
224  auto const address = static_cast<void *>(std::addressof(data_));
225  ::new(address) T(static_cast<Args &&>(args)...);
226  engaged_ = true;
227  return data_;
228  }
229  template(typename I)(
230  requires constructible_from<T, decltype(*std::declval<const I &>())>)
231  T & construct_from_deref(const I & it)
232  {
233  RANGES_EXPECT(!engaged_);
234  auto const address = static_cast<void *>(std::addressof(data_));
235  ::new(address) T(*it);
236  engaged_ = true;
237  return data_;
238  }
239  template<typename U>
240  constexpr void assign_from(U && that) noexcept(
241  std::is_nothrow_constructible<T, decltype(*static_cast<U &&>(that))>::
242  value && std::is_nothrow_assignable<
243  T &, decltype(*static_cast<U &&>(that))>::value)
244  {
245  if(!that.has_value())
246  reset();
247  else if(engaged_)
248  data_ = *static_cast<U &&>(that);
249  else
250  {
251  auto const address =
252  static_cast<void *>(detail::addressof(data_));
253  ::new(address) T(*static_cast<U &&>(that));
254  engaged_ = true;
255  }
256  }
257 
258  private:
259  constexpr void swap_(std::true_type, optional_base & that) noexcept
260  {
261  ranges::swap(static_cast<optional_storage<T> &>(*this),
262  static_cast<optional_storage<T> &>(that));
263  }
264  constexpr void swap_(std::false_type, optional_base & that) noexcept(
265  std::is_nothrow_move_constructible<T>::value &&
266  is_nothrow_swappable<T>::value)
267  {
268  if(that.engaged_ == engaged_)
269  {
270  if(engaged_)
271  ranges::swap(data_, that.data_);
272  }
273  else
274  {
275  auto & src = engaged_ ? *this : that;
276  auto & dst = engaged_ ? that : *this;
277  dst.construct_from(detail::move(src.data_));
278  src.reset();
279  }
280  }
281 
282  using optional_storage<T>::engaged_;
283  using optional_storage<T>::data_;
284  };
285 
286  template<typename T>
287  struct optional_base<T &>
288  {
289  optional_base() = default;
290  template(typename Arg)(
291  requires constructible_from<T &, Arg>)
292  constexpr explicit optional_base(in_place_t, Arg && arg) noexcept //
293  : ptr_(detail::addressof(arg))
294  {}
295  constexpr bool has_value() const noexcept
296  {
297  return ptr_;
298  }
299  constexpr T & operator*() const noexcept
300  {
301  return RANGES_EXPECT(ptr_), *ptr_;
302  }
303  constexpr T * operator->() const noexcept
304  {
305  return RANGES_EXPECT(ptr_), ptr_;
306  }
307  constexpr void reset() noexcept
308  {
309  ptr_ = nullptr;
310  }
311  CPP_member
312  constexpr auto swap(optional_base & that) //
313  noexcept(is_nothrow_swappable<T>::value) //
314  -> CPP_ret(void)(
315  requires swappable<T>)
316  {
317  if(ptr_ && that.ptr_)
318  ranges::swap(*ptr_, *that.ptr_);
319  else
320  ranges::swap(ptr_, that.ptr_);
321  }
322 
323  protected:
324  template(typename U)(
325  requires convertible_to<U &, T &>)
326  constexpr T & construct_from(U && ref) noexcept
327  {
328  RANGES_EXPECT(!ptr_);
329  ptr_ = detail::addressof(ref);
330  return *ptr_;
331  }
332  template<typename U>
333  constexpr void assign_from(U && that)
334  {
335  if(ptr_ && that.ptr_)
336  *ptr_ = *that.ptr_;
337  else
338  ptr_ = that.ptr_;
339  }
340 
341  private:
342  T * ptr_ = nullptr;
343  };
344 
345  template<typename T>
346  struct optional_copy : optional_base<T>
347  {
348  optional_copy() = default;
349  optional_copy(optional_copy const & that) noexcept(
350  std::is_nothrow_copy_constructible<T>::value)
351  {
352  if(that.has_value())
353  this->construct_from(*that);
354  }
355  optional_copy(optional_copy &&) = default;
356  optional_copy & operator=(optional_copy const &) = default;
357  optional_copy & operator=(optional_copy &&) = default;
358 
359  using optional_base<T>::optional_base;
360  };
361 
362  template<typename T>
363  using copy_construct_layer =
364  meta::if_c<std::is_copy_constructible<T>::value &&
365  !detail::is_trivially_copy_constructible_v<T>,
366  optional_copy<T>, optional_base<T>>;
367 
368  template<typename T>
369  struct optional_move : copy_construct_layer<T>
370  {
371  optional_move() = default;
372  optional_move(optional_move const &) = default;
373  optional_move(optional_move && that) noexcept(
374  std::is_nothrow_move_constructible<T>::value)
375  {
376  if(that.has_value())
377  this->construct_from(std::move(*that));
378  }
379  optional_move & operator=(optional_move const &) = default;
380  optional_move & operator=(optional_move &&) = default;
381 
382  using copy_construct_layer<T>::copy_construct_layer;
383  };
384 
385  template<typename T>
386  using move_construct_layer =
387  meta::if_c<std::is_move_constructible<T>::value &&
388  !detail::is_trivially_move_constructible_v<T>,
389  optional_move<T>, copy_construct_layer<T>>;
390 
391  template<typename T>
392  struct optional_copy_assign : move_construct_layer<T>
393  {
394  optional_copy_assign() = default;
395  optional_copy_assign(optional_copy_assign const &) = default;
396  optional_copy_assign(optional_copy_assign &&) = default;
397  optional_copy_assign & operator=(optional_copy_assign const & that) //
398  noexcept(std::is_nothrow_copy_constructible<T>::value &&
399  std::is_nothrow_copy_assignable<T>::value)
400  {
401  this->assign_from(that);
402  return *this;
403  }
404  optional_copy_assign & operator=(optional_copy_assign &&) = default;
405 
406  using move_construct_layer<T>::move_construct_layer;
407  };
408 
409  template<typename T>
410  struct deleted_copy_assign : move_construct_layer<T>
411  {
412  deleted_copy_assign() = default;
413  deleted_copy_assign(deleted_copy_assign const &) = default;
414  deleted_copy_assign(deleted_copy_assign &&) = default;
415  deleted_copy_assign & operator=(deleted_copy_assign const &) = delete;
416  deleted_copy_assign & operator=(deleted_copy_assign &&) = default;
417 
418  using move_construct_layer<T>::move_construct_layer;
419  };
420 
421  template<typename T>
422  using copy_assign_layer = meta::if_c<
423  std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
424  meta::if_c<std::is_reference<T>::value ||
425  !(detail::is_trivially_copy_constructible_v<T> &&
426  detail::is_trivially_copy_assignable_v<T>),
427  optional_copy_assign<T>, move_construct_layer<T>>,
428  deleted_copy_assign<T>>;
429 
430  template<typename T>
431  struct optional_move_assign : copy_assign_layer<T>
432  {
433  optional_move_assign() = default;
434  optional_move_assign(optional_move_assign const &) = default;
435  optional_move_assign(optional_move_assign &&) = default;
436  optional_move_assign & operator=(optional_move_assign const &) = default;
437  optional_move_assign & operator=(optional_move_assign && that) noexcept(
438  std::is_nothrow_move_constructible<T>::value &&
439  std::is_nothrow_move_assignable<T>::value)
440  {
441  this->assign_from(std::move(that));
442  return *this;
443  }
444 
445  using copy_assign_layer<T>::copy_assign_layer;
446  };
447 
448  template<typename T>
449  struct deleted_move_assign : copy_assign_layer<T>
450  {
451  deleted_move_assign() = default;
452  deleted_move_assign(deleted_move_assign const &) = default;
453  deleted_move_assign(deleted_move_assign &&) = default;
454  deleted_move_assign & operator=(deleted_move_assign const &) = default;
455  deleted_move_assign & operator=(deleted_move_assign &&) = delete;
456 
457  using copy_assign_layer<T>::copy_assign_layer;
458  };
459 
460  template<typename T>
461  using move_assign_layer = meta::if_c<
462  std::is_move_constructible<T>::value && std::is_move_assignable<T>::value,
463  meta::if_c<std::is_reference<T>::value ||
464  !(detail::is_trivially_move_constructible_v<T> &&
465  detail::is_trivially_move_assignable_v<T>),
466  optional_move_assign<T>, copy_assign_layer<T>>,
467  deleted_move_assign<T>>;
468  } // namespace optional_adl
469  } // namespace detail
471 
472  // clang-format off
475  template<typename U, typename T>
477  !(
478  constructible_from<T, optional<U> & > ||
479  constructible_from<T, optional<U> && > ||
480  constructible_from<T, optional<U> const & > ||
481  constructible_from<T, optional<U> const &&> ||
482  convertible_to<optional<U> &, T> ||
483  convertible_to<optional<U> &&, T> ||
484  convertible_to<optional<U> const &, T> ||
485  convertible_to<optional<U> const &&, T>
486  );
487 
490  template<typename U, typename T>
492  optional_should_convert<U, T> &&
493  !(assignable_from<T &, optional<U> &> ||
494  assignable_from<T &, optional<U> &&> ||
495  assignable_from<T &, optional<U> const &> ||
496  assignable_from<T &, optional<U> const &&>);
497  // clang-format on
498 
499  template<typename T>
500  struct optional : detail::optional_adl::move_assign_layer<T>
501  {
502  private:
503  using base_t = detail::optional_adl::move_assign_layer<T>;
504 
505  public:
506  CPP_assert(destructible<T>);
507  static_assert(std::is_object<T>::value || std::is_lvalue_reference<T>::value, "");
508  static_assert((bool)!same_as<nullopt_t, uncvref_t<T>>, "");
509  static_assert((bool)!same_as<in_place_t, uncvref_t<T>>, "");
510  using value_type = meta::_t<std::remove_cv<T>>;
511 
512  constexpr optional() noexcept
513  {}
514  constexpr optional(nullopt_t) noexcept
515  : optional{}
516  {}
517  optional(optional const &) = default;
518  optional(optional &&) = default;
519 
520  using base_t::base_t;
521 
522  template(typename E, typename... Args)(
523  requires constructible_from<T, std::initializer_list<E> &, Args...>)
524  constexpr explicit optional(in_place_t, std::initializer_list<E> il,
525  Args &&... args) //
526  noexcept(std::is_nothrow_constructible<T, std::initializer_list<E> &,
527  Args...>::value)
528  : base_t(in_place, il, static_cast<Args &&>(args)...)
529  {}
530 
531 #if defined(__cpp_conditional_explicit) && __cpp_conditional_explicit > 0
532  template(typename U = T)(
533  requires (!same_as<detail::decay_t<U>, in_place_t>) AND
534  (!same_as<detail::decay_t<U>, optional>) AND
535  constructible_from<T, U>)
536  constexpr explicit(!convertible_to<U, T>) optional(U && v)
537  : base_t(in_place, static_cast<U &&>(v))
538  {}
539 
540  template(typename U)(
541  requires optional_should_convert<U, T> AND
542  constructible_from<T, U const &>)
543  explicit(!convertible_to<U const &, T>) optional(optional<U> const & that)
544  {
545  if(that.has_value())
546  base_t::construct_from(*that);
547  }
548 #else
549  template(typename U = T)(
550  requires (!same_as<detail::decay_t<U>, in_place_t>) AND
551  (!same_as<detail::decay_t<U>, optional>) AND
552  constructible_from<T, U> AND
553  convertible_to<U, T>)
554  constexpr optional(U && v)
555  : base_t(in_place, static_cast<U &&>(v))
556  {}
557  template(typename U = T)(
558  requires (!same_as<detail::decay_t<U>, in_place_t>) AND
559  (!same_as<detail::decay_t<U>, optional>) AND
560  constructible_from<T, U> AND
561  (!convertible_to<U, T>))
562  constexpr explicit optional(U && v)
563  : base_t(in_place, static_cast<U &&>(v))
564  {}
565 
566  template(typename U)(
567  requires optional_should_convert<U, T> AND
568  constructible_from<T, U const &> AND
569  convertible_to<U const &, T>)
570  optional(optional<U> const & that)
571  {
572  if(that.has_value())
573  base_t::construct_from(*that);
574  }
575  template(typename U)(
576  requires optional_should_convert<U, T> AND
577  constructible_from<T, U const &> AND
578  (!convertible_to<U const &, T>))
579  explicit optional(optional<U> const & that)
580  {
581  if(that.has_value())
582  base_t::construct_from(*that);
583  }
584 #endif
585 
586  template(typename U)(
587  requires optional_should_convert<U, T> AND constructible_from<T, U> AND
588  convertible_to<U, T>)
589  optional(optional<U> && that)
590  {
591  if(that.has_value())
592  base_t::construct_from(detail::move(*that));
593  }
594  template(typename U)(
595  requires optional_should_convert<U, T> AND constructible_from<T, U> AND
596  (!convertible_to<U, T>)) //
597  explicit optional(optional<U> && that)
598  {
599  if(that.has_value())
600  base_t::construct_from(detail::move(*that));
601  }
602 
603  constexpr optional & operator=(nullopt_t) noexcept
604  {
605  reset();
606  return *this;
607  }
608 
609  optional & operator=(optional const &) = default;
610  optional & operator=(optional &&) = default;
611 
612  template(typename U = T)(
613  requires (!same_as<optional, detail::decay_t<U>>) AND
614  (!(satisfies<T, std::is_scalar> && same_as<T, detail::decay_t<U>>)) AND
615  constructible_from<T, U> AND
616  assignable_from<T &, U>)
617  constexpr optional & operator=(U && u) noexcept(
618  std::is_nothrow_constructible<T, U>::value &&
619  std::is_nothrow_assignable<T &, U>::value)
620  {
621  if(has_value())
622  **this = static_cast<U &&>(u);
623  else
624  base_t::construct_from(static_cast<U &&>(u));
625  return *this;
626  }
627 
628  template(typename U)(
629  requires optional_should_convert_assign<U, T> AND
630  constructible_from<T, const U &> AND
631  assignable_from<T &, const U &>)
632  constexpr optional & operator=(optional<U> const & that)
633  {
634  base_t::assign_from(that);
635  return *this;
636  }
637 
638  template(typename U)(
639  requires optional_should_convert_assign<U, T> AND
640  constructible_from<T, U> AND
641  assignable_from<T &, U>)
642  constexpr optional & operator=(optional<U> && that)
643  {
644  base_t::assign_from(std::move(that));
645  return *this;
646  }
647 
648  template(typename I)(
649  requires constructible_from<T, decltype(*std::declval<const I &>())>)
650  T & emplace_deref(const I & it)
651  {
652  reset();
653  return base_t::construct_from_deref(it);
654  }
655 
656  template(typename... Args)(
657  requires constructible_from<T, Args...>)
658  T & emplace(Args &&... args) noexcept(
659  std::is_nothrow_constructible<T, Args...>::value)
660  {
661  reset();
662  return base_t::construct_from(static_cast<Args &&>(args)...);
663  }
664  template(typename E, typename... Args)(
665  requires constructible_from<T, std::initializer_list<E> &, Args...>)
666  T & emplace(std::initializer_list<E> il, Args &&... args) noexcept(
667  std::is_nothrow_constructible<T, std::initializer_list<E> &, Args...>::value)
668  {
669  reset();
670  return base_t::construct_from(il, static_cast<Args &&>(args)...);
671  }
672 
673  using base_t::swap;
674  using base_t::operator->;
675  using base_t::operator*;
676 
677  constexpr explicit operator bool() const noexcept
678  {
679  return has_value();
680  }
681  using base_t::has_value;
682 
683  constexpr T const & value() const &
684  {
685  return (has_value() || detail::throw_bad_optional_access()), **this;
686  }
687  constexpr T & value() &
688  {
689  return (has_value() || detail::throw_bad_optional_access()), **this;
690  }
691  constexpr T const && value() const &&
692  {
693  return (has_value() || detail::throw_bad_optional_access()),
694  detail::move(**this);
695  }
696  constexpr T && value() &&
697  {
698  return (has_value() || detail::throw_bad_optional_access()),
699  detail::move(**this);
700  }
701 
702  template(typename U)(
703  requires copy_constructible<T> AND convertible_to<U, T>)
704  constexpr T value_or(U && u) const &
705  {
706  return has_value() ? **this : static_cast<T>((U &&) u);
707  }
708  template(typename U)(
709  requires move_constructible<T> AND convertible_to<U, T>)
710  constexpr T value_or(U && u) &&
711  {
712  return has_value() ? detail::move(**this) : static_cast<T>((U &&) u);
713  }
714 
715  using base_t::reset;
716  };
717 
719  namespace detail
720  {
721  namespace optional_adl
722  {
723  constexpr bool convert_bool(bool b) noexcept
724  {
725  return b;
726  }
727 
728  // Relational operators [optional.relops]
729  template<typename T, typename U>
730  constexpr auto operator==(optional<T> const & x, optional<U> const & y) //
731  noexcept(noexcept(convert_bool(*x == *y)))
732  -> decltype(convert_bool(*x == *y))
733  {
734  return x.has_value() == y.has_value() && (!x || convert_bool(*x == *y));
735  }
736  template<typename T, typename U>
737  constexpr auto operator!=(optional<T> const & x, optional<U> const & y) //
738  noexcept(noexcept(convert_bool(*x != *y)))
739  -> decltype(convert_bool(*x != *y))
740  {
741  return x.has_value() != y.has_value() || (x && convert_bool(*x != *y));
742  }
743  template<typename T, typename U>
744  constexpr auto operator<(optional<T> const & x, optional<U> const & y) //
745  noexcept(noexcept(convert_bool(*x < *y)))
746  -> decltype(convert_bool(*x < *y))
747  {
748  return y && (!x || convert_bool(*x < *y));
749  }
750  template<typename T, typename U>
751  constexpr auto operator>(optional<T> const & x, optional<U> const & y) //
752  noexcept(noexcept(convert_bool(*x > *y)))
753  -> decltype(convert_bool(*x > *y))
754  {
755  return x && (!y || convert_bool(*x > *y));
756  }
757  template<typename T, typename U>
758  constexpr auto operator<=(optional<T> const & x, optional<U> const & y) //
759  noexcept(noexcept(convert_bool(*x <= *y)))
760  -> decltype(convert_bool(*x <= *y))
761  {
762  return !x || (y && convert_bool(*x <= *y));
763  }
764  template<typename T, typename U>
765  constexpr auto operator>=(optional<T> const & x, optional<U> const & y) //
766  noexcept(noexcept(convert_bool(*x >= *y)))
767  -> decltype(convert_bool(*x >= *y))
768  {
769  return !y || (x && convert_bool(*x >= *y));
770  }
771 
772  // Comparisons with nullopt [optional.nullops]
773  template<typename T>
774  constexpr bool operator==(optional<T> const & x, nullopt_t) noexcept
775  {
776  return !x;
777  }
778  template<typename T>
779  constexpr bool operator==(nullopt_t, optional<T> const & x) noexcept
780  {
781  return !x;
782  }
783  template<typename T>
784  constexpr bool operator!=(optional<T> const & x, nullopt_t) noexcept
785  {
786  return !!x;
787  }
788  template<typename T>
789  constexpr bool operator!=(nullopt_t, optional<T> const & x) noexcept
790  {
791  return !!x;
792  }
793  template<typename T>
794  constexpr bool operator<(optional<T> const &, nullopt_t) noexcept
795  {
796  return false;
797  }
798  template<typename T>
799  constexpr bool operator<(nullopt_t, optional<T> const & x) noexcept
800  {
801  return !!x;
802  }
803  template<typename T>
804  constexpr bool operator>(optional<T> const & x, nullopt_t) noexcept
805  {
806  return !!x;
807  }
808  template<typename T>
809  constexpr bool operator>(nullopt_t, optional<T> const &) noexcept
810  {
811  return false;
812  }
813  template<typename T>
814  constexpr bool operator<=(optional<T> const & x, nullopt_t) noexcept
815  {
816  return !x;
817  }
818  template<typename T>
819  constexpr bool operator<=(nullopt_t, optional<T> const &) noexcept
820  {
821  return true;
822  }
823  template<typename T>
824  constexpr bool operator>=(optional<T> const &, nullopt_t) noexcept
825  {
826  return true;
827  }
828  template<typename T>
829  constexpr bool operator>=(nullopt_t, optional<T> const & x) noexcept
830  {
831  return !x;
832  }
833 
834  // Comparisons with T [optional.comp_with_t]
835  template<typename T, typename U>
836  constexpr auto operator==(optional<T> const & x, U const & y) //
837  noexcept(noexcept(convert_bool(*x == y))) //
838  -> decltype(convert_bool(*x == y))
839  {
840  return x && convert_bool(*x == y);
841  }
842  template<typename T, typename U>
843  constexpr auto operator==(T const & x, optional<U> const & y) //
844  noexcept(noexcept(convert_bool(x == *y))) //
845  -> decltype(convert_bool(x == *y))
846  {
847  return y && convert_bool(x == *y);
848  }
849  template<typename T, typename U>
850  constexpr auto operator!=(optional<T> const & x, U const & y) //
851  noexcept(noexcept(convert_bool(*x != y))) //
852  -> decltype(convert_bool(*x != y))
853  {
854  return !x || convert_bool(*x != y);
855  }
856  template<typename T, typename U>
857  constexpr auto operator!=(T const & x, optional<U> const & y) //
858  noexcept(noexcept(convert_bool(x != *y))) //
859  -> decltype(convert_bool(x != *y))
860  {
861  return !y || convert_bool(x != *y);
862  }
863  template<typename T, typename U>
864  constexpr auto operator<(optional<T> const & x, U const & y) //
865  noexcept(noexcept(convert_bool(*x < y))) //
866  -> decltype(convert_bool(*x < y))
867  {
868  return !x || convert_bool(*x < y);
869  }
870  template<typename T, typename U>
871  constexpr auto operator<(T const & x, optional<U> const & y) //
872  noexcept(noexcept(convert_bool(x < *y))) //
873  -> decltype(convert_bool(x < *y))
874  {
875  return y && convert_bool(x < *y);
876  }
877  template<typename T, typename U>
878  constexpr auto operator>(optional<T> const & x, U const & y) //
879  noexcept(noexcept(convert_bool(*x > y))) -> decltype(convert_bool(*x > y))
880  {
881  return x && convert_bool(*x > y);
882  }
883  template<typename T, typename U>
884  constexpr auto operator>(T const & x, optional<U> const & y) //
885  noexcept(noexcept(convert_bool(x > *y))) //
886  -> decltype(convert_bool(x > *y))
887  {
888  return !y || convert_bool(x > *y);
889  }
890  template<typename T, typename U>
891  constexpr auto operator<=(optional<T> const & x, U const & y) //
892  noexcept(noexcept(convert_bool(*x <= y))) //
893  -> decltype(convert_bool(*x <= y))
894  {
895  return !x || convert_bool(*x <= y);
896  }
897  template<typename T, typename U>
898  constexpr auto operator<=(T const & x, optional<U> const & y) //
899  noexcept(noexcept(convert_bool(x <= *y))) //
900  -> decltype(convert_bool(x <= *y))
901  {
902  return y && convert_bool(x <= *y);
903  }
904  template<typename T, typename U>
905  constexpr auto operator>=(optional<T> const & x, U const & y) //
906  noexcept(noexcept(convert_bool(*x >= y))) //
907  -> decltype(convert_bool(*x >= y))
908  {
909  return x && convert_bool(*x >= y);
910  }
911  template<typename T, typename U>
912  constexpr auto operator>=(T const & x, optional<U> const & y) //
913  noexcept(noexcept(convert_bool(x >= *y))) //
914  -> decltype(convert_bool(x >= *y))
915  {
916  return !y || convert_bool(x >= *y);
917  }
918 
919  // clang-format off
920  template<typename T>
921  auto CPP_auto_fun(swap)(optional<T> &x, optional<T> &y)
922  (
923  return x.swap(y)
924  )
925  // clang-format on
926  } // namespace optional_adl
927  } // namespace detail
929 
930  // clang-format off
931  template<typename T>
932  constexpr auto CPP_auto_fun(make_optional)(T &&t)
933  (
934  return optional<detail::decay_t<T>>{static_cast<T &&>(t)}
935  )
936  template<typename T, typename... Args>
937  constexpr auto CPP_auto_fun(make_optional)(Args &&... args)
938  (
939  return optional<T>{in_place, static_cast<Args &&>(args)...}
940  )
941  template<typename T, typename U, typename... Args>
942  constexpr auto CPP_auto_fun(make_optional)(std::initializer_list<U> il,
943  Args &&... args)
944  (
945  return optional<T>{in_place, il, static_cast<Args &&>(args)...}
946  )
947  // clang-format on
948 
950  namespace detail
951  {
952  template<typename T, typename Tag = void, bool Enable = true>
953  struct non_propagating_cache : optional<T>
954  {
955  non_propagating_cache() = default;
956  constexpr non_propagating_cache(nullopt_t) noexcept
957  {}
958  constexpr non_propagating_cache(non_propagating_cache const &) noexcept
959  : optional<T>{}
960  {}
961  constexpr non_propagating_cache(non_propagating_cache && that) noexcept
962  : optional<T>{}
963  {
964  that.optional<T>::reset();
965  }
966  constexpr non_propagating_cache & operator=(
967  non_propagating_cache const &) noexcept
968  {
969  optional<T>::reset();
970  return *this;
971  }
972  constexpr non_propagating_cache & operator=(
973  non_propagating_cache && that) noexcept
974  {
975  that.optional<T>::reset();
976  optional<T>::reset();
977  return *this;
978  }
979  using optional<T>::operator=;
980  template<class I>
981  constexpr T & emplace_deref(const I & i)
982  {
983  return optional<T>::emplace(*i);
984  }
985  };
986 
987  template<typename T, typename Tag>
988  struct non_propagating_cache<T, Tag, false>
989  {};
990  } // namespace detail
992 } // namespace ranges
993 
994 #include <range/v3/detail/epilogue.hpp>
995 
996 #endif
std::integral_constant< bool, B > bool_
An integral constant wrapper for bool.
Definition: meta.hpp:168
typename T::type _t
Type alias for T::type.
Definition: meta.hpp:141
Point operator*(double s, const Point &a)
Multiply point by scalar.
Definition: shapes.h:250
CPP_concept optional_should_convert
\concept optional_should_convert
Definition: optional.hpp:476
CPP_concept optional_should_convert_assign
\concept optional_should_convert_assign
Definition: optional.hpp:491
Definition: optional.hpp:38
Definition: in_place.hpp:27
Definition: optional.hpp:48
Definition: optional.hpp:46
Definition: optional.hpp:501