Horizon
Loading...
Searching...
No Matches
optional.hpp
Go to the documentation of this file.
1
2// 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
32namespace 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>
476 CPP_concept optional_should_convert =
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>
491 CPP_concept optional_should_convert_assign =
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)(
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)(
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)(
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)(
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)(
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
The optional_should_convert_assign concept.
The optional_should_convert concept.
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
Definition optional.hpp:38
Definition in_place.hpp:27
Definition optional.hpp:48
Definition optional.hpp:46
Definition optional.hpp:501