sumty  0.1.0
Better sum types for C++
option.hpp
1 /* Copyright 2023 Jack A Bernard Jr.
2  *
3  * Licensed under the Apache License, Version 2.0 (the License);
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an AS IS BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef SUMTY_OPTION_HPP
17 #define SUMTY_OPTION_HPP
18 
19 #include "sumty/detail/fwd.hpp" // IWYU pragma: export
20 #include "sumty/detail/traits.hpp" // IWYU pragma: export
21 #include "sumty/detail/utils.hpp"
22 #include "sumty/exceptions.hpp"
23 #include "sumty/result.hpp" // IWYU pragma: keep
24 #include "sumty/utils.hpp" // IWYU pragma: export
25 #include "sumty/variant.hpp"
26 
27 #include <compare>
28 #include <cstddef>
29 #include <functional>
30 #include <initializer_list>
31 #include <optional>
32 #include <type_traits>
33 #include <utility>
34 
35 namespace sumty {
36 
37 /// @class option option.hpp <sumty/option.hpp>
38 /// @brief Type that either contains some value or none
39 ///
40 /// @details
41 /// @ref option is a reimplementation of `std::optional` with several
42 /// improvements. The key difference is that @ref option can contain `void`
43 /// and references (lvalue and rvalue). `option<void>` turns out to
44 /// essentially be a `bool` with the @ref option interface, and `option<T&>`
45 /// behaves like non-owning, nullable smart pointer to `T`.
46 ///
47 /// Internally, `option<T>` is represented as a @ref variant<void, T>. Thus,
48 /// @ref option benefits from the size optimizations implemented by @ref
49 /// variant (see @ref variant documentation for details). In particular, an
50 /// @ref option of `void` or an empty type has the size of a `bool`, and an
51 /// @ref option of an lvalue reference has the size of a raw pointer.
52 ///
53 /// ```cpp
54 /// struct empty_t {};
55 ///
56 /// assert(sizeof(option<void>) == sizeof(bool));
57 ///
58 /// assert(sizeof(option<empty_t>) == sizeof(bool));
59 ///
60 /// assert(sizeof(option<int&>) == sizeof(int*));
61 ///
62 /// assert(sizeof(option<const int&>) == sizeof(const int*));
63 /// ```
64 ///
65 /// In practice, the benefit of @ref option over `std::optional` is that @ref
66 /// option can be used in more places, espeicially with generic code. A generic
67 /// function (function template) that wants to be able to return a value of any
68 /// type, but also allow that return value to be "null" or "none" can simply
69 /// return a `option<T>`, where `T` is now allowed to be a reference or even
70 /// `void`.
71 ///
72 /// ```cpp
73 /// // Returns the result of invoking func, even if that result is void or a
74 /// // reference, if the condition is true. Otherwise returns none.
75 /// template <typename F>
76 /// option<std::invoke_result_t<F>> call_if(bool condition, F&& func) {
77 /// if (condition) {
78 /// // sumty::invoke needed to handle `void` return type
79 /// return invoke(std::forward<F>(func));
80 /// } else {
81 /// return none;
82 /// }
83 /// }
84 /// ```
85 ///
86 /// An @ref option of an lvalue reference can also be used as an alternative
87 /// to raw pointers is many cases. `option<T&>` communicates that the pointer
88 /// is allowed to be null and that the pointer is non-owning. Depending on a
89 /// project's C++ coding practices, `option<T&>` may be preferable to `T*`, for
90 /// single-object pointers.
91 ///
92 /// @tparam T The possibly contained type
93 template <typename T>
94 class option : variant<void, T> {
95  private:
96  [[nodiscard]] constexpr variant<void, T>& opt_() & noexcept {
97  return *static_cast<variant<void, T>*>(this);
98  }
99 
100  [[nodiscard]] constexpr const variant<void, T>& opt_() const& noexcept {
101  return *static_cast<const variant<void, T>*>(this);
102  }
103 
104  [[nodiscard]] constexpr variant<void, T>&& opt_() && {
105  return std::move(*static_cast<variant<void, T>*>(this));
106  }
107 
108  [[nodiscard]] constexpr variant<void, T>&& opt_() const&& {
109  return std::move(*static_cast<const variant<void, T>*>(this));
110  }
111 
112  public:
113 #ifndef DOXYGEN
114  using value_type = typename detail::traits<T>::value_type;
115  using reference = typename detail::traits<T>::reference;
116  using const_reference = typename detail::traits<T>::const_reference;
117  using rvalue_reference = typename detail::traits<T>::rvalue_reference;
118  using const_rvalue_reference = typename detail::traits<T>::const_rvalue_reference;
119  using pointer = typename detail::traits<T>::pointer;
120  using const_pointer = typename detail::traits<T>::const_pointer;
121 #else
122  using value_type = ...;
123  using reference = ...;
124  using const_reference = ...;
125  using rvalue_reference = ...;
126  using const_rvalue_reference = ...;
127  using pointer = ...;
128  using const_pointer = ...;
129 #endif
130 
131  /// @brief Default constructor
132  ///
133  /// @details
134  /// Initializes the @ref option as none or null.
135  ///
136  /// ## Example
137  /// ```cpp
138  /// option<int> opt;
139  ///
140  /// assert(!opt);
141  ///
142  /// assert(opt.has_value() == false);
143  /// ```
144  constexpr option() noexcept
145 #ifndef DOXYGEN
146  = default;
147 #else
148  ;
149 #endif
150 
151  /// @brief Copy constructor
152  ///
153  /// @details
154  /// If the source @ref option is not none, the new @ref option is
155  /// initialized with a value copy constructed from the value contained in
156  /// the source @ref option.
157  ///
158  /// ## Example
159  /// ```cpp
160  /// option<int> opt1;
161  /// option<int> opt2 = 42;
162  ///
163  /// option<int> opt1_copy{opt1};
164  /// option<int> opt2_copy{opt2};
165  ///
166  /// assert(!opt1_copy);
167  ///
168  /// assert(opt2_copy);
169  /// assert(*opt2_copy == 42);
170  /// ```
171  constexpr option(const option&)
172 #ifndef DOXYGEN
173  noexcept(detail::traits<T>::is_nothrow_copy_constructible) = default;
174 #else
175  CONDITIONALLY_NOEXCEPT;
176 #endif
177 
178  /// @brief Move constructor
179  ///
180  /// @details
181  /// If the source @ref option is not none, the new @ref option is
182  /// initialized with a value move constructed from the value contained in
183  /// the source @ref option.
184  ///
185  /// ## Example
186  /// ```
187  /// option<int> opt1;
188  /// option<int> opt2;
189  ///
190  /// option<int> opt1_moved{std::move(opt1)};
191  /// option<int> opt2_moved{std::move(opt2)};
192  ///
193  /// assert(!opt1_moved);
194  ///
195  /// assert(opt2_moved);
196  /// assert(*opt2_moved == 42);
197  /// ```
198  constexpr option(option&&)
199 #ifndef DOXYGEN
200  noexcept(detail::traits<T>::is_nothrow_move_constructible) = default;
201 #else
202  CONDITIONALLY_NOEXCEPT;
203 #endif
204 
205  /// @brief None constructor
206  ///
207  /// @details
208  /// Initializes the @ref option to the `none` value. That is, the @ref
209  /// option will contain no value, and `.has_value()` will return `false`.
210  ///
211  /// ## Example
212  /// ```
213  /// option<int> opt{none};
214  ///
215  /// assert(!opt);
216  /// assert(opt.has_value() == false);
217  /// assert(opt == none);
218  /// ```
219  // NOLINTNEXTLINE(hicpp-explicit-conversions)
220  constexpr option([[maybe_unused]] none_t null) noexcept : option() {}
221 
222  /// @brief `std::nullopt` constructor
223  ///
224  /// @details
225  /// Initializes the @ref option to the `none` value. That is, the @ref
226  /// option will contain no value, and `.has_value()` will return `false`.
227  ///
228  /// ## Example
229  /// ```
230  /// option<int> opt{std::nullopt};
231  ///
232  /// assert(!opt);
233  /// assert(opt.has_value() == false);
234  /// assert(opt == std::nullopt);
235  /// ```
236  // NOLINTNEXTLINE(hicpp-explicit-conversions)
237  constexpr option([[maybe_unused]] std::nullopt_t null) noexcept : option() {}
238 
239  /// @brief `nullptr` constructor
240  ///
241  /// @details
242  /// Initializes the @ref option to the `none` value. That is, the @ref
243  /// option will contain no value, and `.has_value()` will return `false`.
244  ///
245  /// This constructor only participates in overload resolution if the
246  /// contained value type is an lvalue reference, in which case the @ref
247  /// option behaves like a smart pointer.
248  ///
249  /// ## Example
250  /// ```
251  /// option<int&> opt{nullptr};
252  ///
253  /// assert(!opt);
254  /// assert(opt.has_value() == false);
255  /// assert(opt == nullptr);
256  /// ```
257  // NOLINTNEXTLINE(hicpp-explicit-conversions)
258  constexpr option([[maybe_unused]] std::nullptr_t null) noexcept
259 #ifndef DOXYGEN
260  requires(std::is_lvalue_reference_v<T>)
261 #endif
262  : option() {
263  }
264 
265  /// @brief Pointer constructor
266  ///
267  /// @details
268  /// Initializes the @ref option to contain a reference to the value that
269  /// the pointer points to. If the pointer is null, the @ref option will
270  /// be `none`. That is, the @ref option will contain no value, and
271  /// `.has_value()` will return `false`.
272  ///
273  /// This constructor only participates in overload resolution if the
274  /// contained value type is an lvalue reference, in which case the @ref
275  /// option behaves like a smart pointer.
276  ///
277  /// This constructor is `explicit` if the pointer is not implicitly
278  /// convertible to `T*`.
279  ///
280  /// ## Example
281  /// ```
282  /// int value = 42;
283  /// int* ptr = &value;
284  /// int* null_ptr = nullptr;
285  ///
286  /// option<int&> opt1{ptr};
287  /// option<int&> opt2{null_ptr};
288  ///
289  /// assert(opt1);
290  /// assert(opt1 == ptr);
291  ///
292  /// assert(!opt2);
293  /// assert(opt2 == null_ptr);
294  /// ```
295  template <typename U>
296 #ifndef DOXYGEN
298  explicit(!std::is_convertible_v<U*, pointer>)
299 #else
301 #endif
302  // NOLINTNEXTLINE(hicpp-explicit-conversions)
303  constexpr option(U* ptr) noexcept {
304  if (ptr != nullptr) { opt_().template emplace<1>(*ptr); }
305  }
306 
307  /// @brief Converting copy constructor
308  ///
309  /// @details
310  /// Initializes the @ref option to contain the value of the source @ref
311  /// option where the contained value `U` is converted to `T`, as if by
312  /// `T{U_value}`. If the source @ref option is `none`, then the destination
313  /// @ref option will also be `none`.
314  ///
315  /// This constructor only participates in overload resolution if the
316  /// value type `T` of the destination @ref option is constructible from
317  /// the contained value of the source @ref option `U`.
318  ///
319  /// This constructor is `explicit` if `U` is not implicitly convertible to
320  /// `T`.
321  ///
322  /// ## Example
323  /// ```
324  /// option<float> opt1{3.14};
325  ///
326  /// option<int> opt2{opt1};
327  ///
328  /// assert(opt2);
329  ///
330  /// assert(*opt2 == 3);
331  /// ```
332  template <typename U>
333 #ifndef DOXYGEN
334  requires(std::is_constructible_v<variant<void, T>,
335  std::in_place_index_t<1>,
336  typename detail::traits<U>::const_reference>)
337  explicit(!detail::traits<T>::template is_convertible_from<U>)
338 #else
340 #endif
341  // NOLINTNEXTLINE(hicpp-explicit-conversions)
342  constexpr option(const option<U>& other)
343  : option() {
344  if (other.has_value()) { opt_().template emplace<1>(*other); }
345  }
346 
347  /// @brief Converting move constructor
348  ///
349  /// @details
350  /// Initializes the @ref option to contain the value of the source @ref
351  /// option where the contained value `U` is moved and converted to `T`, as
352  /// if by `T{std::move(U_value)}`. If the source @ref option is `none`,
353  /// the the destination @ref option will also be `none`.
354  ///
355  /// This constructor only participates in overload resolution if the
356  /// value type `T` of the destination @ref option is convertible from
357  /// the contained value of the source @ref option `U`.
358  ///
359  /// This constructor is `explicit` if `U` is not implicitly convertible to
360  /// `T`.
361  ///
362  /// ## Example
363  /// ```
364  /// option<float> opt1{3.14};
365  ///
366  /// option<int> opt2{std::move(opt1)};
367  ///
368  /// assert(opt2);
369  ///
370  /// assert(*opt2 == 3);
371  /// ```
372  template <typename U>
373 #ifndef DOXYGEN
374  requires(std::is_constructible_v<variant<void, T>,
375  std::in_place_index_t<1>,
376  typename detail::traits<U>::rvalue_reference>)
377  explicit(!detail::traits<T>::template is_convertible_from<U>)
378 #else
380 #endif
381  // NOLINTNEXTLINE(hicpp-explicit-conversions)
382  constexpr option(option<U>&& other)
383  : option() {
384  if (other.has_value()) { opt_().template emplace<1>(*std::move(other)); }
385  }
386 
387  /// @brief Emplacement constructor
388  ///
389  /// @details
390  /// The @ref option is initialized such that it contains a value that is
391  /// constructed in place from the forwarded arguments.
392  ///
393  /// This constructor is `explicit` if `inplace` is the only argument.
394  ///
395  /// ## Example
396  /// ```
397  /// option<std::string> opt{std::in_place, 5, 'a'};
398  ///
399  /// assert(opt);
400  ///
401  /// assert(*opt == "aaaaa");
402  /// ```
403  template <typename... Args>
404 #ifndef DOXYGEN
405  explicit(sizeof...(Args) == 0)
406 #else
408 #endif
409  // NOLINTNEXTLINE(hicpp-explicit-conversions)
410  constexpr option([[maybe_unused]] std::in_place_t inplace, Args&&... args)
411  : variant<void, T>(std::in_place_index<1>, std::forward<Args>(args)...) {
412  }
413 
414  /// @brief Emplacement constructor with initializer list
415  ///
416  /// @details
417  /// The @ref option is initialized such that it contains a value that is
418  /// constructed in place from the forwarded arguments.
419  ///
420  /// ## Example
421  /// ```
422  /// option<std::vector<int>> opt{std::in_place, {1, 2, 3, 4, 5}};
423  ///
424  /// assert(opt);
425  ///
426  /// assert(opt->size() == 5);
427  /// ```
428  template <typename U, typename... Args>
429  constexpr option([[maybe_unused]] std::in_place_t inplace,
430  std::initializer_list<U> init,
431  Args&&... args)
432  : variant<void, T>(std::in_place_index<1>, init, std::forward<Args>(args)...) {}
433 
434  /// @brief Forwarding constructor
435  ///
436  /// @details
437  /// The @ref option is initialized such that it contains a value that is
438  /// constructed in place with the passed value forwarded to the value
439  /// type's constructor.
440  ///
441  /// This constructor only participates in overload resolution if the
442  /// contained value type is constructible from the passed value, the passed
443  /// value is not of type `std::in_place_t`, and either the the contained
444  /// value type is not a scalar, or the forwarded value is not an @ref
445  /// option instance.
446  ///
447  /// This constructor is `explicit` if the passed value is not implicitly
448  /// convertible to `T`.
449  ///
450  /// ## Example
451  /// ```
452  /// float value = 3.14;
453  ///
454  /// option<int> opt{value};
455  ///
456  /// assert(opt);
457  ///
458  /// assert(*opt == 3);
459  /// ```
460  template <typename U>
461 #ifndef DOXYGEN
462  requires(detail::traits<T>::template is_constructible<U> &&
466  explicit(!detail::traits<T>::template is_convertible_from<U>)
467 #else
469 #endif
470  // NOLINTNEXTLINE(hicpp-explicit-conversions)
471  constexpr option(U&& value)
472  : variant<void, T>(std::in_place_index<1>, std::forward<U>(value)) {
473  }
474 
475  /// @brief Destructor
476  ///
477  /// @details
478  /// If the @ref option is not `none`, the contained value is destroy in
479  /// place.
480  ///
481  /// The destructor is `noexcept` if the contained value type is nothrow
482  /// destructible.
483  constexpr ~option()
484 #ifndef DOXYGEN
485  noexcept(detail::traits<T>::is_nothrow_destructible) = default;
486 #else
487  CONDITIONALLY_NOEXCEPT;
488 #endif
489 
490  /// @brief Copy assignment operator
491  ///
492  /// @details
493  /// The destination @ref option is reassigned such that it contains the
494  /// value of the source @ref option, if it has any.
495  ///
496  /// If both the source and desitnation @ref option are not `none`, then the
497  /// value contained in the destination @ref option is copy assigned from
498  /// the value contained in the source @ref option.
499  ///
500  /// If the source @ref option contains a value and the destination is
501  /// `none`, the value contained in the source @ref option is destroyed in
502  /// place, making the destination @ref option `none`.
503  ///
504  /// If the source @ref option is `none` and the destination contains a
505  /// value, a new value is copy constructed in place in the source @ref
506  /// option.
507  ///
508  /// If both the source and destination @ref option are `none`, both remain
509  /// `none`.
510  ///
511  /// This function is `noexcept` if the contained value type is nothrow
512  /// copy assignable, nothrow copy constructible, and nothrow destructible.
513  ///
514  /// ## Example
515  /// ```
516  /// option<int> opt1{42};
517  /// option<int> opt2{};
518  ///
519  /// opt2 = opt1;
520  ///
521  /// assert(opt2);
522  /// assert(*opt2 == 42);
523  ///
524  /// opt1 = none;
525  /// opt2 = opt1;
526  ///
527  /// assert(!opt2);
528  /// ```
529  constexpr option& operator=(const option&)
530 #ifndef DOXYGEN
533  detail::traits<T>::is_nothrow_destructible) = default;
534 #else
535  CONDITIONALLY_NOEXCEPT;
536 #endif
537 
538  /// @brief Move assignment operator
539  ///
540  /// @details
541  /// The destination @ref option is reassigned such that it contains the
542  /// moved value of the source @ref option, if it has any. In all cases,
543  /// the source @ref option will be `none` after the move.
544  ///
545  /// If both the source and destination @ref option are not `none`, then the
546  /// value contained in the destination @ref option is move assigned from
547  /// the moved value from the source @ref option. The old value in the
548  /// source @ref option is destroyed in place.
549  ///
550  /// If the source @ref option contains a value and the desitnation is
551  /// `none`, the value contained in the source @ref option is destroyed in
552  /// place, making the desitnation @ref option `none`.
553  ///
554  /// If the source @ref option is `none` and the destination contains a
555  /// value, a new value is move constructed in place in the source @ref
556  /// option. The old value in the source @ref option is destroyed in place.
557  ///
558  /// If both the source and destination @ref option are `none`, both remain
559  /// `none`.
560  ///
561  /// This function is `noexcept` if the contained value type is nothrow
562  /// move assignable, nothrow move constructible, and nothrow destructible.
563  ///
564  /// ## Example
565  /// ```
566  /// option<int> opt1{42};
567  /// option<int> opt2{};
568  ///
569  /// opt2 = std::move(opt1);
570  ///
571  /// assert(!opt1);
572  /// assert(opt2);
573  /// assert(*opt2 == 42);
574  ///
575  /// opt1 = std::move(opt2);
576  ///
577  /// assert(!opt2);
578  /// assert(opt1);
579  /// assert(*opt1 == 42);
580  /// ```
581  constexpr option& operator=(option&&)
582 #ifndef DOXYGEN
585  detail::traits<T>::is_nothrow_destructible) = default;
586 #else
587  CONDITIONALLY_NOEXCEPT;
588 #endif
589 
590  /// @brief `none` assignment operator
591  ///
592  /// @details
593  /// If the @ref option contains a value, the value is destroyed in place.
594  /// If the @ref option is already `none`, this function has no effect.
595  ///
596  /// This function is `noexcept` if the contained value type is nothrow
597  /// destructible.
598  ///
599  /// ## Example
600  /// ```
601  /// option<int> opt{42};
602  ///
603  /// opt = none;
604  ///
605  /// assert(!opt);
606  /// ```
607  constexpr option& operator=([[maybe_unused]] none_t null)
608 #ifndef DOXYGEN
610 #else
612 #endif
613  {
614  opt_().template emplace<0>();
615  return *this;
616  }
617 
618  /// @brief `std::nullopt` assignment operator
619  ///
620  /// @details
621  /// If the @ref option contains a value, the value is destroyed in place.
622  /// If the @ref option is already `none`, this function has no effect.
623  ///
624  /// This function is `noexcept` if the contained value type is nothrow
625  /// destructible.
626  ///
627  /// ## Example
628  /// ```
629  /// option<int> opt{42};
630  ///
631  /// opt = std::nullopt;
632  ///
633  /// assert(!opt);
634  /// ```
635  constexpr option& operator=([[maybe_unused]] std::nullopt_t null)
636 #ifndef DOXYGEN
638 #else
640 #endif
641  {
642  opt_().template emplace<0>();
643  return *this;
644  }
645 
646  /// @brief `nullptr` assignment operator
647  ///
648  /// @details
649  /// Sets an lvalue reference @ref option to `none`.
650  ///
651  /// This function only participates in overload resolution if the contained
652  /// value type is an lvalue reference.
653  ///
654  /// ## Example
655  /// ```
656  /// int value = 42;
657  /// option<int&> opt{value};
658  ///
659  /// opt = nullptr;
660  ///
661  /// assert(!opt);
662  /// ```
663  constexpr option& operator=([[maybe_unused]] std::nullptr_t null) noexcept
664 #ifndef DOXYGEN
665  requires(std::is_lvalue_reference_v<T>)
666 #endif
667  {
668  opt_().template emplace<0>();
669  return *this;
670  }
671 
672  /// @brief Value assignment operator
673  ///
674  /// @details
675  /// Sets the @ref option to contain the provided value, converted to `T`.
676  /// If the @ref option holds a value (is not `none`) before the assigment,
677  /// the value is directly assigned the forwarded source value. If the @ref
678  /// option is `none`, a new value is constructed in place from the
679  /// forwarded source value.
680  ///
681  /// This function only participates in overload resolution if:
682  /// * The source value is not an @ref option
683  /// * `T` is constructible from `U`
684  /// * `T` is assignable from `U`
685  /// * `T` is not scalar or `U` is not equivalent to `T`
686  ///
687  /// ## Example
688  /// ```
689  /// option<long long> opt{};
690  ///
691  /// opt = 42;
692  ///
693  /// assert(opt);
694  ///
695  /// assert(*opt == 42);
696  /// ```
697  template <typename U>
698 #ifndef DOXYGEN
699  requires(
701  std::is_constructible_v<variant<void, T>, std::in_place_index_t<1>, U &&> &&
702  detail::traits<T>::template is_assignable<U &&> &&
704 #endif
705  constexpr option& operator=(U&& value) {
706  if (opt_().index() == 1) {
707  opt_()[index<1>] = std::forward<U>(value);
708  } else {
709  opt_().template emplace<1>(std::forward<U>(value));
710  }
711  return *this;
712  }
713 
714  /// @brief Pointer assignment operator
715  ///
716  /// @details
717  /// The destination @ref option is assigned such that it contains an lvalue
718  /// reference that the source pointer points to. If the pointer is null,
719  /// the destination @ref option will be `none`.
720  ///
721  /// This function only participates in overload resolution if `T` is an
722  /// lvalue reference and the pointer `U*` can be implicitly converted to
723  /// `pointer`.
724  ///
725  /// ## Example
726  /// ```
727  /// int value = 42;
728  /// int* ptr = &value;
729  ///
730  /// option<int&> opt{};
731  ///
732  /// opt = ptr;
733  ///
734  /// assert(opt)
735  ///
736  /// assert(opt == ptr);
737  /// ```
738  template <typename U>
739 #ifndef DOXYGEN
740  requires(std::is_lvalue_reference_v<value_type> &&
742 #endif
743  constexpr option& operator=(U* ptr) noexcept {
744  if (ptr == nullptr) {
745  opt_().template emplace<0>();
746  } else {
747  opt_().template emplace<1>(*ptr);
748  }
749  return *this;
750  }
751 
752  /// @brief Converting copy assignment operator
753  ///
754  /// @details
755  /// This function performs copy assignment just like the standard copy
756  /// assignment operator, but it also performs conversion from the value
757  /// contained in the source @ref option to the value type of contained
758  /// in the destination @ref option.
759  ///
760  /// This function only participates in overload resolution if `T` is not
761  /// construcitble from, convertible from, or assignable from any cvref
762  /// qualified form of `option<U>`, and `T` is both constructible and
763  /// assignable from `U`.
764  ///
765  /// ## Example
766  /// ```
767  /// option<float> opt1{3.14};
768  /// option<int> opt2{};
769  ///
770  /// opt2 = opt1;
771  ///
772  /// assert(opt2);
773  ///
774  /// assert(*opt2 == 3);
775  /// ```
776  template <typename U>
777 #ifndef DOXYGEN
778  requires(!detail::traits<T>::template is_constructible<option<U>&> &&
779  !detail::traits<T>::template is_constructible<const option<U>&> &&
780  !detail::traits<T>::template is_constructible<option<U> &&> &&
781  !detail::traits<T>::template is_constructible<const option<U> &&> &&
782  !detail::traits<T>::template is_convertible_from<option<U>&> &&
783  !detail::traits<T>::template is_convertible_from<const option<U>&> &&
784  !detail::traits<T>::template is_convertible_from<option<U> &&> &&
785  !detail::traits<T>::template is_convertible_from<const option<U> &&> &&
786  !detail::traits<T>::template is_assignable<option<U>&> &&
787  !detail::traits<T>::template is_assignable<const option<U>&> &&
788  !detail::traits<T>::template is_assignable<option<U> &&> &&
789  !detail::traits<T>::template is_assignable<const option<U> &&> &&
791  detail::traits<T>::template is_constructible<
792  typename detail::traits<U>::const_reference>) &&
793  detail::traits<T>::template is_assignable<
794  typename detail::traits<U>::const_reference>)
795 #endif
796  constexpr option& operator=(const option<U>& value) {
797  if (value.has_value()) {
798  opt_().template emplace<1>(*value);
799  } else {
800  opt_().template emplace<0>();
801  }
802  return *this;
803  }
804 
805  /// @brief Converting move assignment operator
806  ///
807  /// @details
808  /// This function performs move assignment just like the standard move
809  /// assignment operator, but it also performs conversion from the value
810  /// contained in the source @ref option to the value type of contained
811  /// in the destination @ref option.
812  ///
813  /// This function only participates in overload resolution if `T` is not
814  /// construcitble from, convertible from, or assignable from any cvref
815  /// qualified form of `option<U>`, and `T` is both constructible and
816  /// assignable from `U`.
817  ///
818  /// ## Example
819  /// ```
820  /// option<float> opt1{3.14};
821  /// option<int> opt2{};
822  ///
823  /// opt2 = std::move(opt1);
824  ///
825  /// assert(opt2);
826  ///
827  /// assert(*opt2 == 3);
828  /// ```
829  template <typename U>
830 #ifndef DOXYGEN
831  requires(!detail::traits<T>::template is_constructible<option<U>&> &&
832  !detail::traits<T>::template is_constructible<const option<U>&> &&
833  !detail::traits<T>::template is_constructible<option<U> &&> &&
834  !detail::traits<T>::template is_constructible<const option<U> &&> &&
835  !detail::traits<T>::template is_convertible_from<option<U>&> &&
836  !detail::traits<T>::template is_convertible_from<const option<U>&> &&
837  !detail::traits<T>::template is_convertible_from<option<U> &&> &&
838  !detail::traits<T>::template is_convertible_from<const option<U> &&> &&
839  !detail::traits<T>::template is_assignable<option<U>&> &&
840  !detail::traits<T>::template is_assignable<const option<U>&> &&
841  !detail::traits<T>::template is_assignable<option<U> &&> &&
842  !detail::traits<T>::template is_assignable<const option<U> &&> &&
844  detail::traits<T>::template is_constructible<
845  typename detail::traits<U>::rvalue_reference>) &&
846  detail::traits<T>::template is_assignable<
847  typename detail::traits<U>::rvalue_reference>)
848 #endif
849  constexpr option& operator=(option<U>&& value) {
850  if (value.has_value()) {
851  opt_().template emplace<1>(*std::move(value));
852  } else {
853  opt_().template emplace<0>();
854  }
855  return *this;
856  }
857 
858  /// @brief Implicit conversion to `bool`.
859  ///
860  /// @details
861  /// This implicit conversion allows an @ref option to be used directly in
862  /// a condition to check if the @ref option contains a value.
863  ///
864  /// ## Example
865  /// ```
866  /// option<int> opt1{};
867  /// option<int> opt2{42};
868  ///
869  /// if (opt1) {
870  /// assert(false);
871  /// } else {
872  /// assert(true);
873  /// }
874  ///
875  /// if (opt2) {
876  /// assert(true);
877  /// } else {
878  /// assert(false);
879  /// }
880  /// ```
881  // NOLINTNEXTLINE(hicpp-explicit-conversions)
882  constexpr operator bool() const noexcept { return opt_().index() != 0; }
883 
884  /// @brief Conversion to raw pointer.
885  ///
886  /// @details
887  /// This conversion allows an @ref option of an lvalue to be converted into
888  /// a raw pointer, where the resulting pointer points to the referenced
889  /// value or is null if the @ref option is none.
890  ///
891  /// This conversion only participates in overload resolution if `T` is an
892  /// lvalue reference and `pointer` can be cast to `U*`.
893  ///
894  /// This conversion is explicit if `pointer` is not implicitly convertible
895  /// to `U*`.
896  ///
897  /// ## Example
898  /// ```
899  /// int value = 42;
900  ///
901  /// option<int&> opt{value};
902  ///
903  /// int* ptr = opt;
904  ///
905  /// assert(ptr == &value);
906  /// ```
907  template <typename U>
908 #ifndef DOXYGEN
909  requires(std::is_lvalue_reference_v<T> &&
910  requires(pointer src, U* dst) { dst = static_cast<U*>(src); })
911  explicit(!std::is_convertible_v<pointer, U*>)
912 #else
914 #endif
915  constexpr
916  // NOLINTNEXTLINE(hicpp-explicit-conversions)
917  operator U*() const noexcept {
918  if (opt_().index() == 0) {
919  return nullptr;
920  } else {
921  return static_cast<U*>(&opt_()[index<1>]);
922  }
923  }
924 
925  /// @brief Returns true if the @ref option contains a value.
926  ///
927  /// @details
928  /// ## Example
929  /// ```
930  /// option<int> opt1{};
931  /// option<int> opt2{42};
932  ///
933  /// assert(opt1.has_value() == false);
934  ///
935  /// assert(opt2.has_value() == true);
936  /// ```
937  [[nodiscard]] constexpr bool has_value() const noexcept { return opt_().index() != 0; }
938 
939  /// @brief Returns true if the @ref option contains a value.
940  ///
941  /// @details
942  /// ## Example
943  /// ```
944  /// option<int> opt1{};
945  /// option<int> opt2{42};
946  ///
947  /// assert(opt1.is_some() == false);
948  ///
949  /// assert(opt2.is_some() == true);
950  /// ```
951  [[nodiscard]] constexpr bool is_some() const noexcept { return opt_().index() != 0; }
952 
953  /// @brief Returns true if the @ref options does not contain a value.
954  ///
955  /// @details
956  /// ## Example
957  /// ```
958  /// option<int> opt1{};
959  /// option<int> opt2{42};
960  ///
961  /// assert(opt1.is_none() == true);
962  ///
963  /// assert(opt2.is_none() == false);
964  /// ```
965  [[nodiscard]] constexpr bool is_none() const noexcept { return opt_().index() == 0; }
966 
967  /// @brief Accesses the value contained in the @ref option.
968  ///
969  /// @details
970  /// This operator does not check if the @ref option contains a value. Use
971  /// of this operator when the @ref option is `none` results in undefined
972  /// behavior.
973  ///
974  /// ## Example
975  /// ```
976  /// option<int> opt{42};
977  ///
978  /// assert(*opt == 42);
979  /// ```
980  [[nodiscard]] constexpr reference operator*() & noexcept { return opt_()[index<1>]; }
981 
982  /// @brief Accesses the value contained in the @ref option.
983  ///
984  /// @details
985  /// This operator does not check if the @ref option contains a value. Use
986  /// of this operator when the @ref option is `none` results in undefined
987  /// behavior.
988  ///
989  /// ## Example
990  /// ```
991  /// const option<int> opt{42};
992  ///
993  /// assert(*opt == 42);
994  /// ```
995  [[nodiscard]] constexpr const_reference operator*() const& noexcept {
996  return opt_()[index<1>];
997  }
998 
999  /// @brief Accesses the value contained in the @ref option.
1000  ///
1001  /// @details
1002  /// This operator does not check if the @ref option contains a value. Use
1003  /// of this operator when the @ref option is `none` results in undefined
1004  /// behavior.
1005  ///
1006  /// ## Example
1007  /// ```
1008  /// option<int> opt{42};
1009  ///
1010  /// assert(*std::move(opt) == 42);
1011  /// ```
1012  [[nodiscard]] constexpr rvalue_reference operator*() && {
1013  return std::move(*this).opt_()[index<1>];
1014  }
1015 
1016  /// @brief Accesses the value contained in the @ref option.
1017  ///
1018  /// @details
1019  /// This operator does not check if the @ref option contains a value. Use
1020  /// of this operator when the @ref option is `none` results in undefined
1021  /// behavior.
1022  ///
1023  /// ## Example
1024  /// ```
1025  /// const option<int> opt{42};
1026  ///
1027  /// assert(*std::move(opt) == 42);
1028  /// ```
1029  [[nodiscard]] constexpr const_rvalue_reference operator*() const&& {
1030  return std::move(*this).opt_()[index<1>];
1031  }
1032 
1033  /// @brief Accesses members of the value contained in the @ref option.
1034  ///
1035  /// @details
1036  /// This operator does not check if the @ref option contains a value. Use
1037  /// of this operator when the @ref option is `none` results in undefined
1038  /// behavior.
1039  ///
1040  /// ## Example
1041  /// ```
1042  /// option<std::string> opt{"hello"};
1043  ///
1044  /// assert(opt->size() == 5);
1045  /// ```
1046  [[nodiscard]] constexpr pointer operator->() noexcept {
1047  return opt_().template get_if<1>();
1048  }
1049 
1050  /// @brief Accesses members of the value contained in the @ref option.
1051  ///
1052  /// @details
1053  /// This operator does not check if the @ref option contains a value. Use
1054  /// of this operator when the @ref option is `none` results in undefined
1055  /// behavior.
1056  ///
1057  /// ## Example
1058  /// ```
1059  /// const option<std::string> opt{"hello"};
1060  ///
1061  /// assert(opt->size() == 5);
1062  /// ```
1063  [[nodiscard]] constexpr const_pointer operator->() const noexcept {
1064  return opt_().template get_if<1>();
1065  }
1066 
1067  /// @brief Accesses the value contained in the @ref option.
1068  ///
1069  /// @details
1070  /// This function first checks if the @ref option contains a value before
1071  /// attempting to access the value. If the @ref option is `none`, then this
1072  /// function throws an exception.
1073  ///
1074  /// ## Example
1075  /// ```
1076  /// option<int> opt{42};
1077  ///
1078  /// assert(opt.value() == 42);
1079  /// ```
1080  ///
1081  /// @throws bad_option_access Thrown if the @ref option is `none`.
1082  [[nodiscard]] constexpr reference value() & {
1083  if (opt_().index() == 0) { throw bad_option_access(); }
1084  return opt_()[index<1>];
1085  }
1086 
1087  /// @brief Accesses the value contained in the @ref option.
1088  ///
1089  /// @details
1090  /// This function first checks if the @ref option contains a value before
1091  /// attempting to access the value. If the @ref option is `none`, then this
1092  /// function throws an exception.
1093  ///
1094  /// ## Example
1095  /// ```
1096  /// const option<int> opt{42};
1097  ///
1098  /// assert(opt.value() == 42);
1099  /// ```
1100  ///
1101  /// @throws bad_option_access Thrown if the @ref option is `none`.
1102  [[nodiscard]] constexpr const_reference value() const& {
1103  if (opt_().index() == 0) { throw bad_option_access(); }
1104  return opt_()[index<1>];
1105  }
1106 
1107  /// @brief Accesses the value contained in the @ref option.
1108  ///
1109  /// @details
1110  /// This function first checks if the @ref option contains a value before
1111  /// attempting to access the value. If the @ref option is `none`, then this
1112  /// function throws an exception.
1113  ///
1114  /// ## Example
1115  /// ```
1116  /// option<int> opt{42};
1117  ///
1118  /// assert(std::move(opt).value() == 42);
1119  /// ```
1120  ///
1121  /// @throws bad_option_access Thrown if the @ref option is `none`.
1122  [[nodiscard]] constexpr rvalue_reference value() && {
1123  if (opt_().index() == 0) { throw bad_option_access(); }
1124  return std::move(*this).opt_()[index<1>];
1125  }
1126 
1127  /// @brief Accesses the value contained in the @ref option.
1128  ///
1129  /// @details
1130  /// This function first checks if the @ref option contains a value before
1131  /// attempting to access the value. If the @ref option is `none`, then this
1132  /// function throws an exception.
1133  ///
1134  /// ## Example
1135  /// ```
1136  /// const option<int> opt{42};
1137  ///
1138  /// assert(std::move(opt).value() == 42);
1139  /// ```
1140  ///
1141  /// @throws bad_option_access Thrown if the @ref option is `none`.
1142  [[nodiscard]] constexpr rvalue_reference value() const&& {
1143  if (opt_().index() == 0) { throw bad_option_access(); }
1144  return std::move(*this).opt_()[index<1>];
1145  }
1146 
1147  /// @brief Gets the @ref option value with a default used for `none`.
1148  ///
1149  /// @details
1150  /// If the @ref option contains a value, a copy of the value is returned.
1151  /// If the @ref option is `none`, the provided default value is returned
1152  /// as `static_cast<T>(std::forward<U>(default_value))`.
1153  ///
1154  /// ## Example
1155  /// ```
1156  /// option<int> opt1{};
1157  /// option<int> opt2{42};
1158  ///
1159  /// assert(opt1.value_or(0) == 0);
1160  ///
1161  /// assert(opt2.value_or(0) == 42);
1162  /// ```
1163  ///
1164  /// @param default_value The value to use if the @ref option is `none`.
1165  template <typename U>
1166  [[nodiscard]] constexpr value_type value_or(U&& default_value) const& {
1167  if (opt_().index() != 0) {
1168  return opt_()[index<1>];
1169  } else {
1170  return static_cast<value_type>(std::forward<U>(default_value));
1171  }
1172  }
1173 
1174  /// @brief Gets the @ref option value with a default used for `none`.
1175  ///
1176  /// @details
1177  /// If the @ref option contains a value, the moved value is returned. If
1178  /// the @ref option is `none`, the provided default value is returned as
1179  /// `static_cast<T>(std::forward<U>(default_value))`.
1180  ///
1181  /// ## Example
1182  /// ```
1183  /// option<int> opt1{};
1184  /// option<int> opt2{42};
1185  ///
1186  /// assert(std::move(opt1).value_or(0) == 0);
1187  ///
1188  /// assert(std::move(opt2).value_or(0) == 42);
1189  /// ```
1190  ///
1191  /// @param default_value The value to use if the @ref option is `none`.
1192  template <typename U>
1193  [[nodiscard]] constexpr value_type value_or(U&& default_value) && {
1194  if (opt_().index() != 0) {
1195  return std::move(*this).opt_()[index<1>];
1196  } else {
1197  return static_cast<value_type>(std::forward<U>(default_value));
1198  }
1199  }
1200 
1201  /// @brief Gets the @ref option value with a default used for `none`.
1202  ///
1203  /// @details
1204  /// If the @ref option contains a value, the copied value is returned. If
1205  /// the @ref option is `none`, the result of invoking `f` is returned. The
1206  /// returned value of `f` is also explicitly cast to `value_type` before
1207  /// return.
1208  ///
1209  /// This function might be preferred over `.value_or(default_value)` when
1210  /// the default value is expensive to create or move. This function allows
1211  /// the default value to never be instantiated if the @ref option is not
1212  /// `none`.
1213  ///
1214  /// ## Example
1215  /// ```
1216  /// option<int> opt1{};
1217  /// option<int> opt2{42};
1218  ///
1219  /// assert(opt1.value_or_else([] { return 0; }) == 0);
1220  ///
1221  /// assert(opt2.value_or_else([] { return 0; }) == 42);
1222  /// ```
1223  ///
1224  /// @param f A callable that creates a default value.
1225  template <typename F>
1226  [[nodiscard]] constexpr value_type value_or_else(F&& f) const& {
1227  if (opt_().index() != 0) {
1228  return opt_()[index<1>];
1229  } else {
1230  return static_cast<value_type>(invoke(std::forward<F>(f)));
1231  }
1232  }
1233 
1234  /// @brief Gets the @ref option value with a default used for `none`.
1235  ///
1236  /// @details
1237  /// If the @ref option contains a value, the moved value is returned. If
1238  /// the @ref option is `none`, the result of invoking `f` is returned. The
1239  /// returned value of `f` is also explicitly cast to `value_type` before
1240  /// return.
1241  ///
1242  /// This function might be preferred over `.value_or(default_value)` when
1243  /// the default value is expensive to create or move. This function allows
1244  /// the default value to never be instantiated if the @ref option is not
1245  /// `none`.
1246  ///
1247  /// ## Example
1248  /// ```
1249  /// option<int> opt1{};
1250  /// option<int> opt2{42};
1251  ///
1252  /// assert(std::move(opt1).value_or_else([] { return 0; }) == 0);
1253  ///
1254  /// assert(std::move(opt2).value_or_else([] { return 0; }) == 42);
1255  /// ```
1256  ///
1257  /// @param f A callable that creates a default value.
1258  template <typename F>
1259  [[nodiscard]] constexpr value_type value_or_else(F&& f) && {
1260  if (opt_().index() != 0) {
1261  return std::move(*this).opt_()[index<1>];
1262  } else {
1263  return static_cast<value_type>(invoke(std::forward<F>(f)));
1264  }
1265  }
1266 
1267  /// @brief Accesses the value contained in the @ref option.
1268  ///
1269  /// @details
1270  /// This function first checks if the @ref option contains a value before
1271  /// attempting to access the value. If the @ref option is `none`, then this
1272  /// function throws an exception.
1273  ///
1274  /// ## Example
1275  /// ```
1276  /// option<int> opt{42};
1277  ///
1278  /// assert(opt.some() == 42);
1279  /// ```
1280  ///
1281  /// @throws bad_option_access Thrown if the @ref option is `none`.
1282  [[nodiscard]] constexpr reference some() & { return value(); }
1283 
1284  /// @brief Accesses the value contained in the @ref option.
1285  ///
1286  /// @details
1287  /// This function first checks if the @ref option contains a value before
1288  /// attempting to access the value. If the @ref option is `none`, then this
1289  /// function throws an exception.
1290  ///
1291  /// ## Example
1292  /// ```
1293  /// const option<int> opt{42};
1294  ///
1295  /// assert(opt.some() == 42);
1296  /// ```
1297  ///
1298  /// @throws bad_option_access Thrown if the @ref option is `none`.
1299  [[nodiscard]] constexpr const_reference some() const& { return value(); }
1300 
1301  /// @brief Accesses the value contained in the @ref option.
1302  ///
1303  /// @details
1304  /// This function first checks if the @ref option contains a value before
1305  /// attempting to access the value. If the @ref option is `none`, then this
1306  /// function throws an exception.
1307  ///
1308  /// ## Example
1309  /// ```
1310  /// option<int> opt{42};
1311  ///
1312  /// assert(std::move(opt).some() == 42);
1313  /// ```
1314  ///
1315  /// @throws bad_option_access Thrown if the @ref option is `none`.
1316  [[nodiscard]] constexpr rvalue_reference some() && { return std::move(*this).value(); }
1317 
1318  /// @brief Accesses the value contained in the @ref option.
1319  ///
1320  /// @details
1321  /// This function first checks if the @ref option contains a value before
1322  /// attempting to access the value. If the @ref option is `none`, then this
1323  /// function throws an exception.
1324  ///
1325  /// ## Example
1326  /// ```
1327  /// const option<int> opt{42};
1328  ///
1329  /// assert(std::move(opt).some() == 42);
1330  /// ```
1331  ///
1332  /// @throws bad_option_access Thrown if the @ref option is `none`.
1333  [[nodiscard]] constexpr rvalue_reference some() const&& {
1334  return std::move(*this).value();
1335  }
1336 
1337  /// @brief Gets the @ref option value with a default used for `none`.
1338  ///
1339  /// @details
1340  /// If the @ref option contains a value, a copy of the value is returned.
1341  /// If the @ref option is `none`, the provided default value is returned
1342  /// as `static_cast<T>(std::forward<U>(default_value))`.
1343  ///
1344  /// ## Example
1345  /// ```
1346  /// option<int> opt1{};
1347  /// option<int> opt2{42};
1348  ///
1349  /// assert(opt1.some_or(0) == 0);
1350  ///
1351  /// assert(opt2.some_or(0) == 42);
1352  /// ```
1353  ///
1354  /// @param default_value The value to use if the @ref option is `none`.
1355  template <typename U>
1356  [[nodiscard]] constexpr value_type some_or(U&& default_value) const& {
1357  return value_or(std::forward<U>(default_value));
1358  }
1359 
1360  /// @brief Gets the @ref option value with a default used for `none`.
1361  ///
1362  /// @details
1363  /// If the @ref option contains a value, the moved value is returned. If
1364  /// the @ref option is `none`, the provided default value is returned as
1365  /// `static_cast<T>(std::forward<U>(default_value))`.
1366  ///
1367  /// ## Example
1368  /// ```
1369  /// option<int> opt1{};
1370  /// option<int> opt2{42};
1371  ///
1372  /// assert(std::move(opt1).some_or(0) == 0);
1373  ///
1374  /// assert(std::move(opt2).some_or(0) == 42);
1375  /// ```
1376  ///
1377  /// @param default_value The value to use if the @ref option is `none`.
1378  template <typename U>
1379  [[nodiscard]] constexpr value_type some_or(U&& default_value) && {
1380  return std::move(*this).value_or(std::forward<U>(default_value));
1381  }
1382 
1383  /// @brief Gets the @ref option value with a default used for `none`.
1384  ///
1385  /// @details
1386  /// If the @ref option contains a value, the copied value is returned. If
1387  /// the @ref option is `none`, the result of invoking `f` is returned. The
1388  /// returned value of `f` is also explicitly cast to `value_type` before
1389  /// return.
1390  ///
1391  /// This function might be preferred over `.value_or(default_value)` when
1392  /// the default value is expensive to create or move. This function allows
1393  /// the default value to never be instantiated if the @ref option is not
1394  /// `none`.
1395  ///
1396  /// ## Example
1397  /// ```
1398  /// option<int> opt1{};
1399  /// option<int> opt2{42};
1400  ///
1401  /// assert(opt1.some_or_else([] { return 0; }) == 0);
1402  ///
1403  /// assert(opt2.some_or_else([] { return 0; }) == 42);
1404  /// ```
1405  ///
1406  /// @param f A callable that creates a default value.
1407  template <typename F>
1408  [[nodiscard]] constexpr value_type some_or_else(F&& f) const& {
1409  return value_or_else(std::forward<F>(f));
1410  }
1411 
1412  /// @brief Gets the @ref option value with a default used for `none`.
1413  ///
1414  /// @details
1415  /// If the @ref option contains a value, the moved value is returned. If
1416  /// the @ref option is `none`, the result of invoking `f` is returned. The
1417  /// returned value of `f` is also explicitly cast to `value_type` before
1418  /// return.
1419  ///
1420  /// This function might be preferred over `.value_or(default_value)` when
1421  /// the default value is expensive to create or move. This function allows
1422  /// the default value to never be instantiated if the @ref option is not
1423  /// `none`.
1424  ///
1425  /// ## Example
1426  /// ```
1427  /// option<int> opt1{};
1428  /// option<int> opt2{42};
1429  ///
1430  /// assert(std::move(opt1).some_or_else([] { return 0; }) == 0);
1431  ///
1432  /// assert(std::move(opt2).some_or_else([] { return 0; }) == 42);
1433  /// ```
1434  ///
1435  /// @param f A callable that creates a default value.
1436  template <typename F>
1437  [[nodiscard]] constexpr value_type some_or_else(F&& f) && {
1438  return std::move(*this).value_or_else(std::forward<F>(f));
1439  }
1440 
1441  /// @brief Converts an @ref option to a @ref result.
1442  ///
1443  /// @details
1444  /// This function constructs and returns a @ref result such that the
1445  /// contained value of the @ref option becomes the `ok` value of the
1446  /// @ref result. If the @ref option is `none`, the provided default
1447  /// value is used as the `error` value of the @ref result.
1448  ///
1449  /// The default error value is always converted to a non-reference. If a
1450  /// reference is desired, use the overload of this function that accepts
1451  /// an @ref error_t.
1452  ///
1453  /// This function only participates in overload resolution if `E` is not
1454  /// an @ref error_t.
1455  ///
1456  /// ## Example
1457  /// ```
1458  /// option<int> opt1{};
1459  /// option<int> opt2{42};
1460  ///
1461  /// result<int, int> res1 = opt1.ok_or(-42);
1462  /// result<int, int> res2 = opt2.ok_or(-42);
1463  ///
1464  /// assert(!res1.has_value());
1465  /// assert(res1.error() == -42);
1466  ///
1467  /// assert(res2.has_value());
1468  /// assert(*res2 == 42);
1469  /// ```
1470  ///
1471  /// @param err The default error value used if the @ref option is `none`.
1472  template <typename E>
1473  [[nodiscard]] constexpr result<T, std::remove_cvref_t<E>> ok_or(E&& err) const& {
1474  if (opt_().index() != 0) {
1475  if constexpr (std::is_void_v<T>) {
1476  return {};
1477  } else {
1478  return opt_()[index<1>];
1479  }
1480  } else {
1481  return result<T, std::remove_cvref_t<E>>{in_place_error, std::forward<E>(err)};
1482  }
1483  }
1484 
1485  /// @brief Converts an @ref option to a @ref result.
1486  ///
1487  /// @details
1488  /// This function constructs and returns a @ref result such that the
1489  /// contained value of the @ref option becomes the `ok` value of the
1490  /// @ref result. If the @ref option is `none`, the provided default
1491  /// value is used as the `error` value of the @ref result.
1492  ///
1493  /// The default error value is always converted to a non-reference. If a
1494  /// reference is desired, use the overload of this function that accepts
1495  /// an @ref error_t.
1496  ///
1497  /// This function only participates in overload resolution if `E` is not
1498  /// an @ref error_t.
1499  ///
1500  /// ## Example
1501  /// ```
1502  /// option<int> opt1{};
1503  /// option<int> opt2{42};
1504  ///
1505  /// result<int, int> res1 = std::move(opt1).ok_or(-42);
1506  /// result<int, int> res2 = std::move(opt2).ok_or(-42);
1507  ///
1508  /// assert(!res1.has_value());
1509  /// assert(res1.error() == -42);
1510  ///
1511  /// assert(res2.has_value());
1512  /// assert(*res2 == 42);
1513  /// ```
1514  ///
1515  /// @param err The default error value used if the @ref option is `none`.
1516  template <typename E>
1517  [[nodiscard]] constexpr result<T, std::remove_cvref_t<E>> ok_or(E&& err) && {
1518  if (opt_().index() != 0) {
1519  if constexpr (std::is_void_v<T>) {
1520  return {};
1521  } else {
1522  return std::move(*this).opt_()[index<1>];
1523  }
1524  } else {
1525  return result<T, std::remove_cvref_t<E>>{in_place_error, std::forward<E>(err)};
1526  }
1527  }
1528 
1529  /// @brief Converts an @ref option to a @ref result.
1530  ///
1531  /// @details
1532  /// This function constructs and returns a @ref result such that the
1533  /// contained value of the @ref option becomes the `ok` value of the
1534  /// @ref result. If the @ref option is `none`, the provided error value
1535  /// is used as the error value of the @ref result.
1536  ///
1537  /// ## Example
1538  /// ```
1539  /// option<int> opt1{};
1540  /// option<int> opt2{42};
1541  ///
1542  /// const auto err = error<int>(-42);
1543  ///
1544  /// result<int, int> res1 = opt1.ok_or(err);
1545  /// result<int, int> res2 = opt2.ok_or(err);
1546  ///
1547  /// assert(!res1.has_value());
1548  /// assert(res1.error() == -42);
1549  ///
1550  /// assert(res2.has_value());
1551  /// assert(*res2 == 42);
1552  /// ```
1553  ///
1554  /// @param err The default error value used if the @ref option is `none`.
1555  template <typename E>
1556  [[nodiscard]] constexpr result<T, E> ok_or(const result<never, E>& err) const& {
1557  if (opt_().index() != 0) {
1558  if constexpr (std::is_void_v<T>) {
1559  return {};
1560  } else {
1561  return opt_()[index<1>];
1562  }
1563  } else {
1564  return err;
1565  }
1566  }
1567 
1568  /// @brief Converts an @ref option to a @ref result.
1569  ///
1570  /// @details
1571  /// This function constructs and returns a @ref result such that the
1572  /// contained value of the @ref option becomes the `ok` value of the
1573  /// @ref result. If the @ref option is `none`, the provided error value
1574  /// is used as the error value of the @ref result.
1575  ///
1576  /// ## Example
1577  /// ```
1578  /// option<int> opt1{};
1579  /// option<int> opt2{42};
1580  ///
1581  /// const auto err = error<int>(-42);
1582  ///
1583  /// result<int, int> res1 = std::move(opt1).ok_or(err);
1584  /// result<int, int> res2 = std::move(opt2).ok_or(err);
1585  ///
1586  /// assert(!res1.has_value());
1587  /// assert(res1.error() == -42);
1588  ///
1589  /// assert(res2.has_value());
1590  /// assert(*res2 == 42);
1591  /// ```
1592  ///
1593  /// @param err The default error value used if the @ref option is `none`.
1594  template <typename E>
1595  [[nodiscard]] constexpr result<T, E> ok_or(const result<never, E>& err) && {
1596  if (opt_().index() != 0) {
1597  if constexpr (std::is_void_v<T>) {
1598  return {};
1599  } else {
1600  return std::move(*this).opt_()[index<1>];
1601  }
1602  } else {
1603  return err;
1604  }
1605  }
1606 
1607  /// @brief Converts an @ref option to a @ref result.
1608  ///
1609  /// @details
1610  /// This function constructs and returns a @ref result such that the
1611  /// contained value of the @ref option becomes the `ok` value of the
1612  /// @ref result. If the @ref option is `none`, the provided error value
1613  /// is used as the error value of the @ref result.
1614  ///
1615  /// ## Example
1616  /// ```
1617  /// option<int> opt1{};
1618  /// option<int> opt2{42};
1619  ///
1620  /// result<int, int> res1 = opt1.ok_or(error<int>(-42));
1621  /// result<int, int> res2 = opt2.ok_or(error<int>(-42));
1622  ///
1623  /// assert(!res1.has_value());
1624  /// assert(res1.error() == -42);
1625  ///
1626  /// assert(res2.has_value());
1627  /// assert(*res2 == 42);
1628  /// ```
1629  ///
1630  /// @param err The default error value used if the @ref option is `none`.
1631  template <typename E>
1632  [[nodiscard]] constexpr result<T, E> ok_or(result<never, E>&& err) const& {
1633  if (opt_().index() != 0) {
1634  if constexpr (std::is_void_v<T>) {
1635  return {};
1636  } else {
1637  return opt_()[index<1>];
1638  }
1639  } else {
1640  return std::move(err);
1641  }
1642  }
1643 
1644  /// @brief Converts an @ref option to a @ref result.
1645  ///
1646  /// @details
1647  /// This function constructs and returns a @ref result such that the
1648  /// contained value of the @ref option becomes the `ok` value of the
1649  /// @ref result. If the @ref option is `none`, the provided error value
1650  /// is used as the error value of the @ref result.
1651  ///
1652  /// ## Example
1653  /// ```
1654  /// option<int> opt1{};
1655  /// option<int> opt2{42};
1656  ///
1657  /// result<int, int> res1 = std::move(opt1).ok_or(error<int>(-42));
1658  /// result<int, int> res2 = std::move(opt2).ok_or(error<int>(-42));
1659  ///
1660  /// assert(!res1.has_value());
1661  /// assert(res1.error() == -42);
1662  ///
1663  /// assert(res2.has_value());
1664  /// assert(*res2 == 42);
1665  /// ```
1666  ///
1667  /// @param err The default error value used if the @ref option is `none`.
1668  template <typename E>
1669  [[nodiscard]] constexpr result<T, E> ok_or(result<never, E>&& err) && {
1670  if (opt_().index() != 0) {
1671  if constexpr (std::is_void_v<T>) {
1672  return {};
1673  } else {
1674  return std::move(*this).opt_()[index<1>];
1675  }
1676  } else {
1677  return std::move(err);
1678  }
1679  }
1680 
1681  /// @brief Converts an @ref option to a @ref result.
1682  ///
1683  /// @details
1684  /// This fucntion constructs and returns a @ref result such that the
1685  /// contained value of the @ref option becomes the `ok` value of the
1686  /// @ref result. If the @ref option is `none`, the result of invoking
1687  /// the provided callable is used as the error value of the @ref result.
1688  ///
1689  /// This function might be preferred over `.ok_or(error_value)` when the
1690  /// error type is expense to construct, copy, or move. This function allows
1691  /// the error value to never be instantiated if the @ref option is not
1692  /// `none`.
1693  ///
1694  /// ## Example
1695  /// ```
1696  /// option<int> opt1{};
1697  /// option<int> opt2{42};
1698  ///
1699  /// result<int, int> res1 = opt1.ok_or_else([] { return -42; });
1700  /// result<int, int> res2 = opt2.ok_or_else([] { return -42; });
1701  ///
1702  /// assert(!res1.has_value());
1703  /// assert(res1.error() == -42);
1704  ///
1705  /// assert(res2.has_value());
1706  /// assert(*res2 == 42);
1707  /// ```
1708  ///
1709  /// @param f A callable that creates a default error value.
1710  template <typename F>
1711  [[nodiscard]] constexpr result<T, std::invoke_result_t<F>> ok_or_else(F&& f) const& {
1712  if (opt_().index() != 0) {
1713  if constexpr (std::is_void_v<T>) {
1714  return {};
1715  } else {
1716  return opt_()[index<1>];
1717  }
1718  } else {
1719  return result<T, std::invoke_result_t<F>>(in_place_error,
1720  invoke(std::forward<F>(f)));
1721  }
1722  }
1723 
1724  /// @brief Converts an @ref option to a @ref result.
1725  ///
1726  /// @details
1727  /// This fucntion constructs and returns a @ref result such that the
1728  /// contained value of the @ref option becomes the `ok` value of the
1729  /// @ref result. If the @ref option is `none`, the result of invoking
1730  /// the provided callable is used as the error value of the @ref result.
1731  ///
1732  /// This function might be preferred over `.ok_or(error_value)` when the
1733  /// error type is expense to construct, copy, or move. This function allows
1734  /// the error value to never be instantiated if the @ref option is not
1735  /// `none`.
1736  ///
1737  /// ## Example
1738  /// ```
1739  /// option<int> opt1{};
1740  /// option<int> opt2{42};
1741  ///
1742  /// result<int, int> res1 = std::move(opt1).ok_or_else([] { return -42; });
1743  /// result<int, int> res2 = std::move(opt2).ok_or_else([] { return -42; });
1744  ///
1745  /// assert(!res1.has_value());
1746  /// assert(res1.error() == -42);
1747  ///
1748  /// assert(res2.has_value());
1749  /// assert(*res2 == 42);
1750  /// ```
1751  ///
1752  /// @param f A callable that creates a default error value.
1753  template <typename F>
1754  [[nodiscard]] constexpr result<T, std::invoke_result_t<F>> ok_or_else(F&& f) && {
1755  if (opt_().index() != 0) {
1756  if constexpr (std::is_void_v<T>) {
1757  return {};
1758  } else {
1759  return std::move(*this).opt_()[index<1>];
1760  }
1761  } else {
1762  return result<T, std::invoke_result_t<F>>(in_place_error,
1763  invoke(std::forward<F>(f)));
1764  }
1765  }
1766 
1767  /// @brief Converts an @ref option to a @ref result.
1768  ///
1769  /// @details
1770  /// This function constructs and returns a @ref result such that the
1771  /// contained value of the @ref option becomes the `error` value of the
1772  /// @ref result. If the @ref option is `none`, the provided default
1773  /// value is used as the `ok` value of the @ref result.
1774  ///
1775  /// The default ok value is always converted to a non-reference. If a
1776  /// reference is desired, use the overload of this function that accepts
1777  /// an @ref ok_t.
1778  ///
1779  /// This function only participates in overload resolution if `U` is not
1780  /// an @ref ok_t.
1781  ///
1782  /// ## Example
1783  /// ```
1784  /// option<int> opt1{};
1785  /// option<int> opt2{42};
1786  ///
1787  /// result<int, int> res1 = opt1.error_or(-42);
1788  /// result<int, int> res2 = opt2.error_or(-42);
1789  ///
1790  /// assert(res1.has_value());
1791  /// assert(*res1 == -42);
1792  ///
1793  /// assert(!res2.has_value());
1794  /// assert(res2.error() == 42);
1795  /// ```
1796  ///
1797  /// @param err The default ok value used if the @ref option is `none`.
1798  template <typename U>
1799  [[nodiscard]] constexpr result<std::remove_cvref_t<U>, T> error_or(U&& value) const& {
1800  if (opt_().index() != 0) {
1801  if constexpr (std::is_void_v<T>) {
1802  return result<std::remove_cvref_t<U>, T>{in_place_error};
1803  } else {
1804  return result<std::remove_cvref_t<U>, T>{in_place_error, opt_()[index<1>]};
1805  }
1806  } else {
1807  return result<std::remove_cvref_t<U>, T>{std::in_place, std::forward<U>(value)};
1808  }
1809  }
1810 
1811  /// @brief Converts an @ref option to a @ref result.
1812  ///
1813  /// @details
1814  /// This function constructs and returns a @ref result such that the
1815  /// contained value of the @ref option becomes the `error` value of the
1816  /// @ref result. If the @ref option is `none`, the provided default
1817  /// value is used as the `ok` value of the @ref result.
1818  ///
1819  /// The default ok value is always converted to a non-reference. If a
1820  /// reference is desired, use the overload of this function that accepts
1821  /// an @ref ok_t.
1822  ///
1823  /// This function only participates in overload resolution if `U` is not
1824  /// an @ref ok_t.
1825  ///
1826  /// ## Example
1827  /// ```
1828  /// option<int> opt1{};
1829  /// option<int> opt2{42};
1830  ///
1831  /// result<int, int> res1 = std::move(opt1).error_or(-42);
1832  /// result<int, int> res2 = std::move(opt2).error_or(-42);
1833  ///
1834  /// assert(res1.has_value());
1835  /// assert(*res1 == -42);
1836  ///
1837  /// assert(!res2.has_value());
1838  /// assert(res2.error() == 42);
1839  /// ```
1840  ///
1841  /// @param err The default ok value used if the @ref option is `none`.
1842  template <typename U>
1843  [[nodiscard]] constexpr result<std::remove_cvref_t<U>, T> error_or(U&& value) && {
1844  if (opt_().index() != 0) {
1845  if constexpr (std::is_void_v<T>) {
1846  return result<std::remove_cvref_t<U>, T>{in_place_error};
1847  } else {
1848  return result<std::remove_cvref_t<U>, T>{in_place_error,
1849  std::move(*this).opt_()[index<1>]};
1850  }
1851  } else {
1852  return result<std::remove_cvref_t<U>, T>{std::in_place, std::forward<U>(value)};
1853  }
1854  }
1855 
1856  /// @brief Converts an @ref option to a @ref result.
1857  ///
1858  /// @details
1859  /// This function constructs and returns a @ref result such that the
1860  /// contained value of the @ref option becomes the `error` value of the
1861  /// @ref result. If the @ref option is `none`, the provided default
1862  /// value is used as the `ok` value of the @ref result.
1863  ///
1864  /// ## Example
1865  /// ```
1866  /// option<int> opt1{};
1867  /// option<int> opt2{42};
1868  ///
1869  /// const auto value = ok<int>(-42);
1870  ///
1871  /// result<int, int> res1 = opt1.error_or(value);
1872  /// result<int, int> res2 = opt2.error_or(value);
1873  ///
1874  /// assert(res1.has_value());
1875  /// assert(*res1 == -42);
1876  ///
1877  /// assert(!res2.has_value());
1878  /// assert(res2.error() == 42);
1879  /// ```
1880  ///
1881  /// @param err The default ok value used if the @ref option is `none`.
1882  template <typename U>
1883  [[nodiscard]] constexpr result<U, T> error_or(const result<U, never>& value) const& {
1884  if (opt_().index() != 0) {
1885  if constexpr (std::is_void_v<T>) {
1886  return result<U, T>{in_place_error};
1887  } else {
1888  return result<U, T>{in_place_error, opt_()[index<1>]};
1889  }
1890  } else {
1891  return value;
1892  }
1893  }
1894 
1895  /// @brief Converts an @ref option to a @ref result.
1896  ///
1897  /// @details
1898  /// This function constructs and returns a @ref result such that the
1899  /// contained value of the @ref option becomes the `error` value of the
1900  /// @ref result. If the @ref option is `none`, the provided default
1901  /// value is used as the `ok` value of the @ref result.
1902  ///
1903  /// ## Example
1904  /// ```
1905  /// option<int> opt1{};
1906  /// option<int> opt2{42};
1907  ///
1908  /// const auto value = ok<int>(-42);
1909  ///
1910  /// result<int, int> res1 = std::move(opt1).error_or(value);
1911  /// result<int, int> res2 = std::move(opt2).error_or(value);
1912  ///
1913  /// assert(res1.has_value());
1914  /// assert(*res1 == -42);
1915  ///
1916  /// assert(!res2.has_value());
1917  /// assert(res2.error() == 42);
1918  /// ```
1919  ///
1920  /// @param err The default ok value used if the @ref option is `none`.
1921  template <typename U>
1922  [[nodiscard]] constexpr result<U, T> error_or(const result<U, never>& value) && {
1923  if (opt_().index() != 0) {
1924  if constexpr (std::is_void_v<T>) {
1925  return result<U, T>{in_place_error};
1926  } else {
1927  return result<U, T>{in_place_error, std::move(*this).opt_()[index<1>]};
1928  }
1929  } else {
1930  return value;
1931  }
1932  }
1933 
1934  /// @brief Converts an @ref option to a @ref result.
1935  ///
1936  /// @details
1937  /// This function constructs and returns a @ref result such that the
1938  /// contained value of the @ref option becomes the `error` value of the
1939  /// @ref result. If the @ref option is `none`, the provided default
1940  /// value is used as the `ok` value of the @ref result.
1941  ///
1942  /// ## Example
1943  /// ```
1944  /// option<int> opt1{};
1945  /// option<int> opt2{42};
1946  ///
1947  /// result<int, int> res1 = opt1.error_or(ok<int>(-42));
1948  /// result<int, int> res2 = opt2.error_or(ok<int>(-42));
1949  ///
1950  /// assert(res1.has_value());
1951  /// assert(*res1 == -42);
1952  ///
1953  /// assert(!res2.has_value());
1954  /// assert(res2.error() == 42);
1955  /// ```
1956  ///
1957  /// @param err The default ok value used if the @ref option is `none`.
1958  template <typename U>
1959  [[nodiscard]] constexpr result<U, T> error_or(result<U, never>&& value) const& {
1960  if (opt_().index() != 0) {
1961  if constexpr (std::is_void_v<T>) {
1962  return result<U, T>{in_place_error};
1963  } else {
1964  return result<U, T>{in_place_error, opt_()[index<1>]};
1965  }
1966  } else {
1967  return std::move(value);
1968  }
1969  }
1970 
1971  /// @brief Converts an @ref option to a @ref result.
1972  ///
1973  /// @details
1974  /// This function constructs and returns a @ref result such that the
1975  /// contained value of the @ref option becomes the `error` value of the
1976  /// @ref result. If the @ref option is `none`, the provided default
1977  /// value is used as the `ok` value of the @ref result.
1978  ///
1979  /// ## Example
1980  /// ```
1981  /// option<int> opt1{};
1982  /// option<int> opt2{42};
1983  ///
1984  /// result<int, int> res1 = std::move(opt1).error_or(ok<int>(-42));
1985  /// result<int, int> res2 = std::move(opt2).error_or(ok<int>(-42));
1986  ///
1987  /// assert(res1.has_value());
1988  /// assert(*res1 == -42);
1989  ///
1990  /// assert(!res2.has_value());
1991  /// assert(res2.error() == 42);
1992  /// ```
1993  ///
1994  /// @param err The default ok value used if the @ref option is `none`.
1995  template <typename U>
1996  [[nodiscard]] constexpr result<U, T> error_or(result<U, never>&& value) && {
1997  if (opt_().index() != 0) {
1998  if constexpr (std::is_void_v<T>) {
1999  return result<U, T>{in_place_error};
2000  } else {
2001  return result<U, T>{in_place_error, std::move(*this).opt_()[index<1>]};
2002  }
2003  } else {
2004  return std::move(value);
2005  }
2006  }
2007 
2008  /// @brief Converts an @ref option to a @ref result.
2009  ///
2010  /// @details
2011  /// This fucntion constructs and returns a @ref result such that the
2012  /// contained value of the @ref option becomes the `error` value of the
2013  /// @ref result. If the @ref option is `none`, the result of invoking
2014  /// the provided callable is used as the `ok` value of the @ref result.
2015  ///
2016  /// This function might be preferred over `.error_or(ok_value)` when the
2017  /// value type is expensive to construct, copy, or move. This function
2018  /// allows the value to never be instantiated if the @ref option is not
2019  /// `none`.
2020  ///
2021  /// ## Example
2022  /// ```
2023  /// option<int> opt1{};
2024  /// option<int> opt2{42};
2025  ///
2026  /// result<int, int> res1 = opt1.error_or_else([] { return -42; });
2027  /// result<int, int> res2 = opt2.error_or_else([] { return -42; });
2028  ///
2029  /// assert(res1.has_value());
2030  /// assert(*res1 == -42);
2031  ///
2032  /// assert(!res2.has_value());
2033  /// assert(res2.error() == 42);
2034  /// ```
2035  ///
2036  /// @param f A callable that creates a default ok value.
2037  template <typename F>
2038  [[nodiscard]] constexpr result<std::invoke_result_t<F>, T> error_or_else(F&& f) const& {
2039  if (opt_().index() != 0) {
2040  if constexpr (std::is_void_v<T>) {
2041  return result<std::invoke_result_t<F>, T>{in_place_error};
2042  } else {
2043  return result<std::invoke_result_t<F>, T>{in_place_error, opt_()[index<1>]};
2044  }
2045  } else {
2046  return result<std::invoke_result_t<F>, T>{std::in_place,
2047  invoke(std::forward<F>(f))};
2048  }
2049  }
2050 
2051  /// @brief Converts an @ref option to a @ref result.
2052  ///
2053  /// @details
2054  /// This fucntion constructs and returns a @ref result such that the
2055  /// contained value of the @ref option becomes the `error` value of the
2056  /// @ref result. If the @ref option is `none`, the result of invoking
2057  /// the provided callable is used as the `ok` value of the @ref result.
2058  ///
2059  /// This function might be preferred over `.error_or(ok_value)` when the
2060  /// value type is expensive to construct, copy, or move. This function
2061  /// allows the value to never be instantiated if the @ref option is not
2062  /// `none`.
2063  ///
2064  /// ## Example
2065  /// ```
2066  /// option<int> opt1{};
2067  /// option<int> opt2{42};
2068  ///
2069  /// result<int, int> res1 = std::move(opt1).error_or_else([] {
2070  /// return -42;
2071  /// });
2072  /// result<int, int> res2 = std::move(opt2).error_or_else([] {
2073  /// return -42;
2074  /// });
2075  ///
2076  /// assert(res1.has_value());
2077  /// assert(*res1 == -42);
2078  ///
2079  /// assert(!res2.has_value());
2080  /// assert(res2.error() == 42);
2081  /// ```
2082  ///
2083  /// @param f A callable that creates a default ok value.
2084  template <typename F>
2085  [[nodiscard]] constexpr result<std::invoke_result_t<F>, T> error_or_else(F&& f) && {
2086  if (opt_().index() != 0) {
2087  if constexpr (std::is_void_v<T>) {
2088  return result<std::invoke_result_t<F>, T>{in_place_error};
2089  } else {
2090  return result<std::invoke_result_t<F>, T>{
2091  in_place_error, std::move(*this).opt_()[index<1>]};
2092  }
2093  } else {
2094  return result<std::invoke_result_t<F>, T>{std::in_place,
2095  invoke(std::forward<F>(f))};
2096  }
2097  }
2098 
2099  /// @brief Converts an @ref option into an @ref option of a reference.
2100  ///
2101  /// @details
2102  /// This function acts as a monadic operation that gets a reference to the
2103  /// contained value without unwrapping the @ref option. In the case where
2104  /// the contained value is `void`, the returned @ref option is also `void`.
2105  ///
2106  /// ## Example
2107  /// ```
2108  /// option<int> opt1{};
2109  /// option<int> opt2{42};
2110  ///
2111  /// option<int&> opt1_ref = opt1.ref();
2112  /// option<int&> opt2_ref = opt2.ref();
2113  ///
2114  /// assert(opt1_ref == nullptr);
2115  /// assert(opt2_ref == &*opt2);
2116  /// ```
2117  [[nodiscard]] constexpr option<reference> ref() noexcept {
2118  if (opt_().index() != 0) {
2119  return option<reference>{std::in_place, opt_()[index<1>]};
2120  } else {
2121  return option<reference>{};
2122  }
2123  }
2124 
2125  /// @brief Converts an @ref option into an @ref option of a reference.
2126  ///
2127  /// @details
2128  /// This function acts as a monadic operation that gets a reference to the
2129  /// contained value without unwrapping the @ref option. In the case where
2130  /// the contained value is `void`, the returned @ref option is also `void`.
2131  ///
2132  /// ## Example
2133  /// ```
2134  /// const option<int> opt1{};
2135  /// const option<int> opt2{42};
2136  ///
2137  /// option<const int&> opt1_ref = opt1.ref();
2138  /// option<const int&> opt2_ref = opt2.ref();
2139  ///
2140  /// assert(opt1_ref == nullptr);
2141  /// assert(opt2_ref == &*opt2);
2142  /// ```
2143  [[nodiscard]] constexpr option<const_reference> ref() const noexcept {
2144  if (opt_().index() != 0) {
2145  return option<const_reference>{std::in_place, opt_()[index<1>]};
2146  } else {
2147  return option<const_reference>{};
2148  }
2149  }
2150 
2151  /// @brief Converts an @ref option into an @ref option of a reference.
2152  ///
2153  /// @details
2154  /// This function acts as a monadic operation that gets a reference to the
2155  /// contained value without unwrapping the @ref option. In the case where
2156  /// the contained value is `void`, the returned @ref option is also `void`.
2157  ///
2158  /// ## Example
2159  /// ```
2160  /// option<int> opt1{};
2161  /// option<int> opt2{42};
2162  ///
2163  /// option<const int&> opt1_ref = opt1.cref();
2164  /// option<const int&> opt2_ref = opt2.cref();
2165  ///
2166  /// assert(opt1_ref == nullptr);
2167  /// assert(opt2_ref == &*opt2);
2168  /// ```
2169  [[nodiscard]] constexpr option<const_reference> cref() const noexcept { return ref(); }
2170 
2171  /// @brief Applies a callable to the contents of an @ref option.
2172  ///
2173  /// @details
2174  /// If the @ref option contains a value, the value is passed into the
2175  /// callable, and the invocation result is returned from this function.
2176  /// If the @ref option is `none`, the callable is not invoked and `none`
2177  /// is returned.
2178  ///
2179  /// This function only participates in overload resolution if the
2180  /// invocation result of the callable is an @ref option.
2181  ///
2182  /// ## Example
2183  /// ```
2184  /// option<int> opt1{};
2185  /// option<int> opt2{42};
2186  /// option<int> opt3{-42};
2187  ///
2188  /// auto callable = [](int value) -> option<unsigned int> {
2189  /// if (value < 0) {
2190  /// return none;
2191  /// } else {
2192  /// return static_cast<unsigned int>(value);
2193  /// }
2194  /// };
2195  ///
2196  /// auto opt1_res = opt1.and_then(callable);
2197  /// auto opt2_res = opt2.and_then(callable);
2198  /// auto opt3_res = opt3.and_then(callable);
2199  ///
2200  /// assert(!opt1_res.has_value());
2201  ///
2202  /// assert(opt2_res.has_value());
2203  /// assert(*opt2_res == 42);
2204  ///
2205  /// assert(!opt3_res.has_value());
2206  /// ```
2207  ///
2208  /// @param f Callable applied to the contained option value
2209  template <typename F>
2210 #ifndef DOXYGEN
2211  requires(
2213 #endif
2214  constexpr auto and_then(F&& f) & {
2215  if constexpr (std::is_void_v<reference>) {
2216  if (opt_().index() != 0) {
2217  return std::invoke(std::forward<F>(f), void_v);
2218  } else {
2219  return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{};
2220  }
2221  } else {
2222  if (opt_().index() != 0) {
2223  return std::invoke(std::forward<F>(f), opt_()[index<1>]);
2224  } else {
2225  return std::remove_cvref_t<std::invoke_result_t<F, reference>>{};
2226  }
2227  }
2228  }
2229 
2230  /// @brief Applies a callable to the contents of an @ref option.
2231  ///
2232  /// @details
2233  /// If the @ref option contains a value, the value is passed into the
2234  /// callable, and the invocation result is returned from this function.
2235  /// If the @ref option is `none`, the callable is not invoked and `none`
2236  /// is returned.
2237  ///
2238  /// This function only participates in overload resolution if the
2239  /// invocation result of the callable is an @ref option.
2240  ///
2241  /// ## Example
2242  /// ```
2243  /// const option<int> opt1{};
2244  /// const option<int> opt2{42};
2245  /// const option<int> opt3{-42};
2246  ///
2247  /// auto callable = [](int value) -> option<unsigned int> {
2248  /// if (value < 0) {
2249  /// return none;
2250  /// } else {
2251  /// return static_cast<unsigned int>(value);
2252  /// }
2253  /// };
2254  ///
2255  /// auto opt1_res = opt1.and_then(callable);
2256  /// auto opt2_res = opt2.and_then(callable);
2257  /// auto opt3_res = opt3.and_then(callable);
2258  ///
2259  /// assert(!opt1_res.has_value());
2260  ///
2261  /// assert(opt2_res.has_value());
2262  /// assert(*opt2_res == 42);
2263  ///
2264  /// assert(!opt3_res.has_value());
2265  /// ```
2266  ///
2267  /// @param f Callable applied to the contained option value
2268  template <typename F>
2269 #ifndef DOXYGEN
2270  requires(detail::is_option_v<
2272 #endif
2273  constexpr auto and_then(F&& f) const& {
2274  if constexpr (std::is_void_v<const_reference>) {
2275  if (opt_().index() != 0) {
2276  return std::invoke(std::forward<F>(f), void_v);
2277  } else {
2278  return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{};
2279  }
2280  } else {
2281  if (opt_().index() != 0) {
2282  return std::invoke(std::forward<F>(f), opt_()[index<1>]);
2283  } else {
2284  return std::remove_cvref_t<std::invoke_result_t<F, const_reference>>{};
2285  }
2286  }
2287  }
2288 
2289  /// @brief Applies a callable to the contents of an @ref option.
2290  ///
2291  /// @details
2292  /// If the @ref option contains a value, the value is passed into the
2293  /// callable, and the invocation result is returned from this function.
2294  /// If the @ref option is `none`, the callable is not invoked and `none`
2295  /// is returned.
2296  ///
2297  /// This function only participates in overload resolution if the
2298  /// invocation result of the callable is an @ref option.
2299  ///
2300  /// ## Example
2301  /// ```
2302  /// option<int> opt1{};
2303  /// option<int> opt2{42};
2304  /// option<int> opt3{-42};
2305  ///
2306  /// auto callable = [](int value) -> option<unsigned int> {
2307  /// if (value < 0) {
2308  /// return none;
2309  /// } else {
2310  /// return static_cast<unsigned int>(value);
2311  /// }
2312  /// };
2313  ///
2314  /// auto opt1_res = std::move(opt1).and_then(callable);
2315  /// auto opt2_res = std::move(opt2).and_then(callable);
2316  /// auto opt3_res = std::move(opt3).and_then(callable);
2317  ///
2318  /// assert(!opt1_res.has_value());
2319  ///
2320  /// assert(opt2_res.has_value());
2321  /// assert(*opt2_res == 42);
2322  ///
2323  /// assert(!opt3_res.has_value());
2324  /// ```
2325  ///
2326  /// @param f Callable applied to the contained option value
2327  template <typename F>
2328 #ifndef DOXYGEN
2329  requires(detail::is_option_v<
2331 #endif
2332  constexpr auto and_then(F&& f) && {
2333  if constexpr (std::is_void_v<rvalue_reference>) {
2334  if (opt_().index() != 0) {
2335  return std::invoke(std::forward<F>(f), void_v);
2336  } else {
2337  return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{};
2338  }
2339  } else {
2340  if (opt_().index() != 0) {
2341  return std::invoke(std::forward<F>(f), std::move(*this).opt_()[index<1>]);
2342  } else {
2343  return std::remove_cvref_t<std::invoke_result_t<F, rvalue_reference>>{};
2344  }
2345  }
2346  }
2347 
2348  /// @brief Applies a callable to the contents of an @ref option.
2349  ///
2350  /// @details
2351  /// If the @ref option contains a value, the value is passed into the
2352  /// callable, and the invocation result is returned from this function.
2353  /// If the @ref option is `none`, the callable is not invoked and `none`
2354  /// is returned.
2355  ///
2356  /// This function only participates in overload resolution if the
2357  /// invocation result of the callable is an @ref option.
2358  ///
2359  /// ## Example
2360  /// ```
2361  /// const option<int> opt1{};
2362  /// const option<int> opt2{42};
2363  /// const option<int> opt3{-42};
2364  ///
2365  /// auto callable = [](int value) -> option<unsigned int> {
2366  /// if (value < 0) {
2367  /// return none;
2368  /// } else {
2369  /// return static_cast<unsigned int>(value);
2370  /// }
2371  /// };
2372  ///
2373  /// auto opt1_res = std::move(opt1).and_then(callable);
2374  /// auto opt2_res = std::move(opt2).and_then(callable);
2375  /// auto opt3_res = std::move(opt3).and_then(callable);
2376  ///
2377  /// assert(!opt1_res.has_value());
2378  ///
2379  /// assert(opt2_res.has_value());
2380  /// assert(*opt2_res == 42);
2381  ///
2382  /// assert(!opt3_res.has_value());
2383  /// ```
2384  ///
2385  /// @param f Callable applied to the contained option value
2386  template <typename F>
2387 #ifndef DOXYGEN
2388  requires(detail::is_option_v<
2390 #endif
2391  constexpr auto and_then(F&& f) const&& {
2392  if constexpr (std::is_void_v<const_rvalue_reference>) {
2393  if (opt_().index() != 0) {
2394  return std::invoke(std::forward<F>(f), void_v);
2395  } else {
2396  return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{};
2397  }
2398  } else {
2399  if (opt_().index() != 0) {
2400  return std::invoke(std::forward<F>(f), std::move(*this).opt_()[index<1>]);
2401  } else {
2402  return std::remove_cvref_t<
2403  std::invoke_result_t<F, const_rvalue_reference>>{};
2404  }
2405  }
2406  }
2407 
2408  /// @brief Performs a transformation on the content of an @ref option.
2409  ///
2410  /// @details
2411  /// This function is a monadic operation that passes the value contained
2412  /// in the @ref option, if any, to the callable `f`. The value returned by
2413  /// the call to `f` is then returned from this function wrapped in a new
2414  /// @ref option. If the original @ref option is `none`, the returned value
2415  /// is a `none` @ref option of the type that would have been returned by
2416  /// `f`.
2417  ///
2418  /// Note that this function is identical to @ref map, but the name
2419  /// `transform` make @ref option able to be a drop in replacement for
2420  /// `std::optional`. `map` is the more typical name of this monadic
2421  /// operation outside of C++.
2422  ///
2423  /// ## Example
2424  /// ```
2425  /// option<int> opt1{};
2426  /// option<int> opt2{42};
2427  ///
2428  /// auto opt1_mapped = opt1.transform([](auto value) {
2429  /// return std::to_string(value);
2430  /// });
2431  /// auto opt2_mapped = opt2.transform([](auto value) {
2432  /// return std::to_string(value);
2433  /// });
2434  ///
2435  /// assert(!opt1_mapped.has_value());
2436  ///
2437  /// assert(opt2_mapped.has_value());
2438  /// assert(*opt2_mapped = "42");
2439  /// ```
2440  ///
2441  /// @param f A callable that transforms the @ref option value
2442  template <typename F>
2443  constexpr auto transform(F&& f) & {
2444  if constexpr (std::is_void_v<reference>) {
2445  using res_t = std::invoke_result_t<F, void_t>;
2446  if (opt_().index() != 0) {
2447  if constexpr (std::is_void_v<res_t>) {
2448  std::invoke(std::forward<F>(f), void_v);
2449  return option<res_t>{std::in_place};
2450  } else {
2451  return option<res_t>{std::in_place,
2452  std::invoke(std::forward<F>(f), void_v)};
2453  }
2454  } else {
2455  return option<res_t>{};
2456  }
2457  } else {
2458  using res_t = std::invoke_result_t<F, reference>;
2459  if (opt_().index() != 0) {
2460  if constexpr (std::is_void_v<res_t>) {
2461  std::invoke(std::forward<F>(f), opt_()[index<1>]);
2462  return option<res_t>{std::in_place};
2463  } else {
2464  return option<res_t>{std::in_place,
2465  std::invoke(std::forward<F>(f), opt_()[index<1>])};
2466  }
2467  } else {
2468  return option<res_t>{};
2469  }
2470  }
2471  }
2472 
2473  /// @brief Performs a transformation on the content of an @ref option.
2474  ///
2475  /// @details
2476  /// This function is a monadic operation that passes the value contained
2477  /// in the @ref option, if any, to the callable `f`. The value returned by
2478  /// the call to `f` is then returned from this function wrapped in a new
2479  /// @ref option. If the original @ref option is `none`, the returned value
2480  /// is a `none` @ref option of the type that would have been returned by
2481  /// `f`.
2482  ///
2483  /// Note that this function is identical to @ref map, but the name
2484  /// `transform` make @ref option able to be a drop in replacement for
2485  /// `std::optional`. `map` is the more typical name of this monadic
2486  /// operation outside of C++.
2487  ///
2488  /// ## Example
2489  /// ```
2490  /// const option<int> opt1{};
2491  /// const option<int> opt2{42};
2492  ///
2493  /// auto opt1_mapped = opt1.transform([](auto value) {
2494  /// return std::to_string(value);
2495  /// });
2496  /// auto opt2_mapped = opt2.transform([](auto value) {
2497  /// return std::to_string(value);
2498  /// });
2499  ///
2500  /// assert(!opt1_mapped.has_value());
2501  ///
2502  /// assert(opt2_mapped.has_value());
2503  /// assert(*opt2_mapped = "42");
2504  /// ```
2505  ///
2506  /// @param f A callable that transforms the @ref option value
2507  template <typename F>
2508  constexpr auto transform(F&& f) const& {
2509  if constexpr (std::is_void_v<const_reference>) {
2510  using res_t = std::invoke_result_t<F, void_t>;
2511  if (opt_().index() != 0) {
2512  if constexpr (std::is_void_v<res_t>) {
2513  std::invoke(std::forward<F>(f), void_v);
2514  return option<res_t>{std::in_place};
2515  } else {
2516  return option<res_t>{std::in_place,
2517  std::invoke(std::forward<F>(f), void_v)};
2518  }
2519  } else {
2520  return option<res_t>{};
2521  }
2522  } else {
2523  using res_t = std::invoke_result_t<F, const_reference>;
2524  if (opt_().index() != 0) {
2525  if constexpr (std::is_void_v<res_t>) {
2526  std::invoke(std::forward<F>(f), opt_()[index<1>]);
2527  return option<res_t>{std::in_place};
2528  } else {
2529  return option<res_t>{std::in_place,
2530  std::invoke(std::forward<F>(f), opt_()[index<1>])};
2531  }
2532  } else {
2533  return option<res_t>{};
2534  }
2535  }
2536  }
2537 
2538  /// @brief Performs a transformation on the content of an @ref option.
2539  ///
2540  /// @details
2541  /// This function is a monadic operation that passes the value contained
2542  /// in the @ref option, if any, to the callable `f`. The value returned by
2543  /// the call to `f` is then returned from this function wrapped in a new
2544  /// @ref option. If the original @ref option is `none`, the returned value
2545  /// is a `none` @ref option of the type that would have been returned by
2546  /// `f`.
2547  ///
2548  /// Note that this function is identical to @ref map, but the name
2549  /// `transform` make @ref option able to be a drop in replacement for
2550  /// `std::optional`. `map` is the more typical name of this monadic
2551  /// operation outside of C++.
2552  ///
2553  /// ## Example
2554  /// ```
2555  /// option<int> opt1{};
2556  /// option<int> opt2{42};
2557  ///
2558  /// auto opt1_mapped = std::move(opt1).transform([](auto value) {
2559  /// return std::to_string(value);
2560  /// });
2561  /// auto opt2_mapped = std::move(opt2).transform([](auto value) {
2562  /// return std::to_string(value);
2563  /// });
2564  ///
2565  /// assert(!opt1_mapped.has_value());
2566  ///
2567  /// assert(opt2_mapped.has_value());
2568  /// assert(*opt2_mapped = "42");
2569  /// ```
2570  ///
2571  /// @param f A callable that transforms the @ref option value
2572  template <typename F>
2573  constexpr auto transform(F&& f) && {
2574  if constexpr (std::is_void_v<rvalue_reference>) {
2575  using res_t = std::invoke_result_t<F, void_t>;
2576  if (opt_().index() != 0) {
2577  if constexpr (std::is_void_v<res_t>) {
2578  std::invoke(std::forward<F>(f), void_v);
2579  return option<res_t>{std::in_place};
2580  } else {
2581  return option<res_t>{std::in_place,
2582  std::invoke(std::forward<F>(f), void_v)};
2583  }
2584  } else {
2585  return option<res_t>{};
2586  }
2587  } else {
2588  using res_t = std::invoke_result_t<F, rvalue_reference>;
2589  if (opt_().index() != 0) {
2590  if constexpr (std::is_void_v<res_t>) {
2591  std::invoke(std::forward<F>(f), std::move(*this).opt_()[index<1>]);
2592  return option<res_t>{std::in_place};
2593  } else {
2594  return option<res_t>{
2595  std::in_place,
2596  std::invoke(std::forward<F>(f), std::move(*this).opt_()[index<1>])};
2597  }
2598  } else {
2599  return option<res_t>{};
2600  }
2601  }
2602  }
2603 
2604  /// @brief Performs a transformation on the content of an @ref option.
2605  ///
2606  /// @details
2607  /// This function is a monadic operation that passes the value contained
2608  /// in the @ref option, if any, to the callable `f`. The value returned by
2609  /// the call to `f` is then returned from this function wrapped in a new
2610  /// @ref option. If the original @ref option is `none`, the returned value
2611  /// is a `none` @ref option of the type that would have been returned by
2612  /// `f`.
2613  ///
2614  /// Note that this function is identical to @ref map, but the name
2615  /// `transform` make @ref option able to be a drop in replacement for
2616  /// `std::optional`. `map` is the more typical name of this monadic
2617  /// operation outside of C++.
2618  ///
2619  /// ## Example
2620  /// ```
2621  /// const option<int> opt1{};
2622  /// const option<int> opt2{42};
2623  ///
2624  /// auto opt1_mapped = std::move(opt1).transform([](auto value) {
2625  /// return std::to_string(value);
2626  /// });
2627  /// auto opt2_mapped = std::move(opt2).transform([](auto value) {
2628  /// return std::to_string(value);
2629  /// });
2630  ///
2631  /// assert(!opt1_mapped.has_value());
2632  ///
2633  /// assert(opt2_mapped.has_value());
2634  /// assert(*opt2_mapped = "42");
2635  /// ```
2636  ///
2637  /// @param f A callable that transforms the @ref option value
2638  template <typename F>
2639  constexpr auto transform(F&& f) const&& {
2640  if constexpr (std::is_void_v<const_rvalue_reference>) {
2641  using res_t = std::invoke_result_t<F, void_t>;
2642  if (opt_().index() != 0) {
2643  if constexpr (std::is_void_v<res_t>) {
2644  std::invoke(std::forward<F>(f), void_v);
2645  return option<res_t>{std::in_place};
2646  } else {
2647  return option<res_t>{std::in_place,
2648  std::invoke(std::forward<F>(f), void_v)};
2649  }
2650  } else {
2651  return option<res_t>{};
2652  }
2653  } else {
2654  using res_t = std::invoke_result_t<F, const_rvalue_reference>;
2655  if (opt_().index() != 0) {
2656  if constexpr (std::is_void_v<res_t>) {
2657  std::invoke(std::forward<F>(f), std::move(*this).opt_()[index<1>]);
2658  return option<res_t>{std::in_place};
2659  } else {
2660  return option<res_t>{
2661  std::in_place,
2662  std::invoke(std::forward<F>(f), std::move(*this).opt_()[index<1>])};
2663  }
2664  } else {
2665  return option<res_t>{};
2666  }
2667  }
2668  }
2669 
2670  /// @brief Performs a transformation on the content of an @ref option.
2671  ///
2672  /// @details
2673  /// This function is a monadic operation that passes the value contained
2674  /// in the @ref option, if any, to the callable `f`. The value returned by
2675  /// the call to `f` is then returned from this function wrapped in a new
2676  /// @ref option. If the original @ref option is `none`, the returned value
2677  /// is a `none` @ref option of the type that would have been returned by
2678  /// `f`.
2679  ///
2680  /// Note that this function is identical to @ref transform, but the name
2681  /// `map` is the more typical name of this monadic operation outside of
2682  /// C++.
2683  ///
2684  /// ## Example
2685  /// ```
2686  /// option<int> opt1{};
2687  /// option<int> opt2{42};
2688  ///
2689  /// auto opt1_mapped = opt1.map([](auto value) {
2690  /// return std::to_string(value);
2691  /// });
2692  /// auto opt2_mapped = opt2.map([](auto value) {
2693  /// return std::to_string(value);
2694  /// });
2695  ///
2696  /// assert(!opt1_mapped.has_value());
2697  ///
2698  /// assert(opt2_mapped.has_value());
2699  /// assert(*opt2_mapped = "42");
2700  /// ```
2701  ///
2702  /// @param f A callable that maps the @ref option value
2703  template <typename F>
2704  constexpr auto map(F&& f) & {
2705  return transform(std::forward<F>(f));
2706  }
2707 
2708  /// @brief Performs a transformation on the content of an @ref option.
2709  ///
2710  /// @details
2711  /// This function is a monadic operation that passes the value contained
2712  /// in the @ref option, if any, to the callable `f`. The value returned by
2713  /// the call to `f` is then returned from this function wrapped in a new
2714  /// @ref option. If the original @ref option is `none`, the returned value
2715  /// is a `none` @ref option of the type that would have been returned by
2716  /// `f`.
2717  ///
2718  /// Note that this function is identical to @ref transform, but the name
2719  /// `map` is the more typical name of this monadic operation outside of
2720  /// C++.
2721  ///
2722  /// ## Example
2723  /// ```
2724  /// const option<int> opt1{};
2725  /// const option<int> opt2{42};
2726  ///
2727  /// auto opt1_mapped = opt1.map([](auto value) {
2728  /// return std::to_string(value);
2729  /// });
2730  /// auto opt2_mapped = opt2.map([](auto value) {
2731  /// return std::to_string(value);
2732  /// });
2733  ///
2734  /// assert(!opt1_mapped.has_value());
2735  ///
2736  /// assert(opt2_mapped.has_value());
2737  /// assert(*opt2_mapped = "42");
2738  /// ```
2739  ///
2740  /// @param f A callable that maps the @ref option value
2741  template <typename F>
2742  constexpr auto map(F&& f) const& {
2743  return transform(std::forward<F>(f));
2744  }
2745 
2746  /// @brief Performs a transformation on the content of an @ref option.
2747  ///
2748  /// @details
2749  /// This function is a monadic operation that passes the value contained
2750  /// in the @ref option, if any, to the callable `f`. The value returned by
2751  /// the call to `f` is then returned from this function wrapped in a new
2752  /// @ref option. If the original @ref option is `none`, the returned value
2753  /// is a `none` @ref option of the type that would have been returned by
2754  /// `f`.
2755  ///
2756  /// Note that this function is identical to @ref transform, but the name
2757  /// `map` is the more typical name of this monadic operation outside of
2758  /// C++.
2759  ///
2760  /// ## Example
2761  /// ```
2762  /// option<int> opt1{};
2763  /// option<int> opt2{42};
2764  ///
2765  /// auto opt1_mapped = std::move(opt1).map([](auto value) {
2766  /// return std::to_string(value);
2767  /// });
2768  /// auto opt2_mapped = std::move(opt2).map([](auto value) {
2769  /// return std::to_string(value);
2770  /// });
2771  ///
2772  /// assert(!opt1_mapped.has_value());
2773  ///
2774  /// assert(opt2_mapped.has_value());
2775  /// assert(*opt2_mapped = "42");
2776  /// ```
2777  ///
2778  /// @param f A callable that maps the @ref option value
2779  template <typename F>
2780  constexpr auto map(F&& f) && {
2781  return std::move(*this).transform(std::forward<F>(f));
2782  }
2783 
2784  /// @brief Performs a transformation on the content of an @ref option.
2785  ///
2786  /// @details
2787  /// This function is a monadic operation that passes the value contained
2788  /// in the @ref option, if any, to the callable `f`. The value returned by
2789  /// the call to `f` is then returned from this function wrapped in a new
2790  /// @ref option. If the original @ref option is `none`, the returned value
2791  /// is a `none` @ref option of the type that would have been returned by
2792  /// `f`.
2793  ///
2794  /// Note that this function is identical to @ref transform, but the name
2795  /// `map` is the more typical name of this monadic operation outside of
2796  /// C++.
2797  ///
2798  /// ## Example
2799  /// ```
2800  /// const option<int> opt1{};
2801  /// const option<int> opt2{42};
2802  ///
2803  /// auto opt1_mapped = std::move(opt1).map([](auto value) {
2804  /// return std::to_string(value);
2805  /// });
2806  /// auto opt2_mapped = std::move(opt2).map([](auto value) {
2807  /// return std::to_string(value);
2808  /// });
2809  ///
2810  /// assert(!opt1_mapped.has_value());
2811  ///
2812  /// assert(opt2_mapped.has_value());
2813  /// assert(*opt2_mapped = "42");
2814  /// ```
2815  ///
2816  /// @param f A callable that maps the @ref option value
2817  template <typename F>
2818  constexpr auto map(F&& f) const&& {
2819  return std::move(*this).transform(std::forward<F>(f));
2820  }
2821 
2822  /// @brief Returns the result of `f` if the @ref option is `none`.
2823  ///
2824  /// @details
2825  /// If the @ref option contains a value, a copy of the @ref option is
2826  /// returned. Otherwise, the result of invoking `f` is returned.
2827  ///
2828  /// ## Example
2829  /// ```
2830  /// option<int> opt1{};
2831  /// option<int> opt2{42};
2832  ///
2833  /// auto opt1_new = opt1.or_else([] { return 0; });
2834  /// auto opt2_new = opt2.or_else([] { return 0; });
2835  ///
2836  /// assert(opt1_new.has_value());
2837  /// assert(*opt1_new == 0);
2838  ///
2839  /// assert(opt2_new.has_value());
2840  /// assert(*opt2_new == 42);
2841  /// ```
2842  ///
2843  /// @param f A callable that returns the "else" @ref option
2844  template <typename F>
2845  constexpr option or_else(F&& f) const& {
2846  if (opt_().index() != 0) {
2847  return *this;
2848  } else {
2849  return std::invoke(std::forward<F>(f));
2850  }
2851  }
2852 
2853  /// @brief Returns the result of `f` if the @ref option is `none`.
2854  ///
2855  /// @details
2856  /// If the @ref option contains a value, a copy of the @ref option is
2857  /// returned. Otherwise, the result of invoking `f` is returned.
2858  ///
2859  /// ## Example
2860  /// ```
2861  /// option<int> opt1{};
2862  /// option<int> opt2{42};
2863  ///
2864  /// auto opt1_new = std::move(opt1).or_else([] { return 0; });
2865  /// auto opt2_new = std::move(opt2).or_else([] { return 0; });
2866  ///
2867  /// assert(opt1_new.has_value());
2868  /// assert(*opt1_new == 0);
2869  ///
2870  /// assert(opt2_new.has_value());
2871  /// assert(*opt2_new == 42);
2872  /// ```
2873  ///
2874  /// @param f A callable that returns the "else" @ref option
2875  template <typename F>
2876  constexpr option or_else(F&& f) && {
2877  if (opt_().index() != 0) {
2878  return std::move(*this);
2879  } else {
2880  return std::invoke(std::forward<F>(f));
2881  }
2882  }
2883 
2884  /// @brief Converts `option<option<T>>` to `option<T>`
2885  ///
2886  /// @details
2887  /// If the outer @ref option is `none` or the inner @ref option is `none`,
2888  /// `none` is returned. Otherwise the flattend @ref option with a contained
2889  /// value is returned.
2890  ///
2891  /// Note that only one level of @ref option is removed. An
2892  /// `option<option<option<T>>>` will flatten to an `option<option<T>>`.
2893  ///
2894  /// This function only participates in overload resolution if `T` is an
2895  /// @ref option.
2896  ///
2897  /// ## Example
2898  /// ```
2899  /// option<option<int>> opt1{};
2900  /// option<option<int>> opt2 = some<option<int>>(none);
2901  /// option<option<int>> opt3 = some<option<int>>(42);
2902  ///
2903  /// auto opt1_flat = opt1.flatten();
2904  /// auto opt2_flat = opt2.flatten();
2905  /// auto opt3_flat = opt3.flatten();
2906  ///
2907  /// assert(opt1_flat.is_none());
2908  /// assert(opt2_flat.is_none());
2909  ///
2910  /// assert(opt3_flat.is_some());
2911  /// assert(*opt3_flat = 42);
2912  /// ```
2913  [[nodiscard]] constexpr T flatten() const&
2914 #ifndef DOXYGEN
2915  requires(detail::is_option_v<T>)
2916 #endif
2917  {
2918  return value_or_else([]() -> T { return none; });
2919  }
2920 
2921  /// @brief Converts `option<option<T>>` to `option<T>`
2922  ///
2923  /// @details
2924  /// If the outer @ref option is `none` or the inner @ref option is `none`,
2925  /// `none` is returned. Otherwise the flattend @ref option with a contained
2926  /// value is returned.
2927  ///
2928  /// Note that only one level of @ref option is removed. An
2929  /// `option<option<option<T>>>` will flatten to an `option<option<T>>`.
2930  ///
2931  /// This function only participates in overload resolution if `T` is an
2932  /// @ref option.
2933  ///
2934  /// ## Example
2935  /// ```
2936  /// option<option<int>> opt1{};
2937  /// option<option<int>> opt2 = some<option<int>>(none);
2938  /// option<option<int>> opt3 = some<option<int>>(42);
2939  ///
2940  /// auto opt1_flat = std::move(opt1).flatten();
2941  /// auto opt2_flat = std::move(opt2).flatten();
2942  /// auto opt3_flat = std::move(opt3).flatten();
2943  ///
2944  /// assert(opt1_flat.is_none());
2945  /// assert(opt2_flat.is_none());
2946  ///
2947  /// assert(opt3_flat.is_some());
2948  /// assert(*opt3_flat = 42);
2949  /// ```
2950  [[nodiscard]] constexpr T flatten() &&
2951 #ifndef DOXYGEN
2952  requires(detail::is_option_v<T>)
2953 #endif
2954  {
2955  return std::move(*this).value_or_else([]() -> T { return none; });
2956  }
2957 
2958  /// @brief Converts nested @ref option types into a single @ref option
2959  ///
2960  /// @details
2961  /// Like @ref flatten, this function removes nested layers of @ref option,
2962  /// such as converting `option<option<T>>` into `option<T>`. However,
2963  /// unlike @ref flatten, this function removes all layers of nesting and
2964  /// works for unnested @ref option types. For example,
2965  /// `option<option<option<T>>>` is converted directly to `option<T>`, and
2966  /// for `option<T>`, where `T` is not an @ref option type, no layers of
2967  /// @ref option are removed.
2968  ///
2969  /// ## Example
2970  /// ```
2971  /// option<option<option<int>>> opt1{in_place, in_place, in_place, 42};
2972  /// option<option<option<int>>> opt2{none};
2973  /// option<option<option<int>>> opt3{in_place, none};
2974  /// option<option<option<int>>> opt4{in_place, in_place, none};
2975  ///
2976  /// option<int> opt1_flat = opt1.flatten_all();
2977  /// option<int> opt2_flat = opt2.flatten_all();
2978  /// option<int> opt3_flat = opt3.flatten_all();
2979  /// option<int> opt4_flat = opt4.flatten_all();
2980  ///
2981  /// assert(opt1_flat.is_some());
2982  /// assert(*opt1_flat == 42);
2983  ///
2984  /// assert(opt2_flat.is_none());
2985  /// assert(opt3_flat.is_none());
2986  /// assert(opt4_flat.is_none());
2987  /// ```
2988  [[nodiscard]] constexpr auto flatten_all() const& {
2989  if constexpr (detail::is_option_v<T>) {
2990  return flatten().flatten_all();
2991  } else {
2992  return *this;
2993  }
2994  }
2995 
2996  /// @brief Converts nested @ref option types into a single @ref option
2997  ///
2998  /// @details
2999  /// Like @ref flatten, this function removes nested layers of @ref option,
3000  /// such as converting `option<option<T>>` into `option<T>`. However,
3001  /// unlike @ref flatten, this function removes all layers of nesting and
3002  /// works for unnested @ref option types. For example,
3003  /// `option<option<option<T>>>` is converted directly to `option<T>`, and
3004  /// for `option<T>`, where `T` is not an @ref option type, no layers of
3005  /// @ref option are removed.
3006  ///
3007  /// ## Example
3008  /// ```
3009  /// option<option<option<int>>> opt1{in_place, in_place, in_place, 42};
3010  /// option<option<option<int>>> opt2{none};
3011  /// option<option<option<int>>> opt3{in_place, none};
3012  /// option<option<option<int>>> opt4{in_place, in_place, none};
3013  ///
3014  /// option<int> opt1_flat = std::move(opt1).flatten_all();
3015  /// option<int> opt2_flat = std::move(opt2).flatten_all();
3016  /// option<int> opt3_flat = std::move(opt3).flatten_all();
3017  /// option<int> opt4_flat = std::move(opt4).flatten_all();
3018  ///
3019  /// assert(opt1_flat.is_some());
3020  /// assert(*opt1_flat == 42);
3021  ///
3022  /// assert(opt2_flat.is_none());
3023  /// assert(opt3_flat.is_none());
3024  /// assert(opt4_flat.is_none());
3025  /// ```
3026  [[nodiscard]] constexpr auto flatten_all() && {
3027  if constexpr (detail::is_option_v<T>) {
3028  return std::move(*this).flatten().flatten_all();
3029  } else {
3030  return std::move(*this);
3031  }
3032  }
3033 
3034  /// @brief Filters the @ref option based on a predicate
3035  ///
3036  /// @details
3037  /// If the @ref option is already `none`, `none` is returned. If the @ref
3038  /// option contains a value, the returned value depends on the predicate.
3039  /// If the predicate returns `true`, an @ref option with a copy of the
3040  /// original contained value is returned. Otherwise, `none` is returned.
3041  ///
3042  /// The predicate must have a signature compatible with:
3043  /// `bool pred(const T&)`.
3044  ///
3045  /// ## Example
3046  /// ```
3047  /// option<int> opt1{};
3048  /// option<int> opt2{42};
3049  /// option<int> opt3{-42};
3050  ///
3051  /// auto opt1_filt = opt1.filter([](int val) { return val > 0; });
3052  /// auto opt2_filt = opt2.filter([](int val) { return val > 0; });
3053  /// auto opt3_filt = opt3.filter([](int val) { return val > 0; });
3054  ///
3055  /// assert(opt1_filt.is_none());
3056  ///
3057  /// assert(opt2_filt.is_some());
3058  /// assert(*opt2_filt == 42);
3059  ///
3060  /// assert(opt3_filt.is_none());
3061  /// ```
3062  template <typename Pred>
3063  constexpr option filter(Pred&& pred) const& {
3064  if constexpr (std::is_void_v<T>) {
3065  if (is_some() && std::invoke(std::forward<Pred>(pred), void_v)) {
3066  return *this;
3067  } else {
3068  return none;
3069  }
3070  } else {
3071  if (is_some() && std::invoke(std::forward<Pred>(pred), opt_()[index<1>])) {
3072  return *this;
3073  } else {
3074  return none;
3075  }
3076  }
3077  }
3078 
3079  /// @brief Filters the @ref option based on a predicate
3080  ///
3081  /// @details
3082  /// If the @ref option is already `none`, `none` is returned. If the @ref
3083  /// option contains a value, the returned value depends on the predicate.
3084  /// If the predicate returns `true`, an @ref option with the moved
3085  /// original contained value is returned. Otherwise, `none` is returned.
3086  ///
3087  /// The predicate must have a signature compatible with:
3088  /// `bool pred(T&)` or `bool pred(const T&)`.
3089  ///
3090  /// ## Example
3091  /// ```
3092  /// option<int> opt1{};
3093  /// option<int> opt2{42};
3094  /// option<int> opt3{-42};
3095  ///
3096  /// auto opt1_filt = std::move(opt1).filter([](int val) {
3097  /// return val > 0;
3098  /// });
3099  /// auto opt2_filt = std::move(opt2).filter([](int val) {
3100  /// return val > 0;
3101  /// });
3102  /// auto opt3_filt = std::move(opt3).filter([](int val) {
3103  /// return val > 0;
3104  /// });
3105  ///
3106  /// assert(opt1_filt.is_none());
3107  ///
3108  /// assert(opt2_filt.is_some());
3109  /// assert(*opt2_filt == 42);
3110  ///
3111  /// assert(opt3_filt.is_none());
3112  /// ```
3113  template <typename Pred>
3114  constexpr option filter(Pred&& pred) && {
3115  if constexpr (std::is_void_v<T>) {
3116  if (is_some() && std::invoke(std::forward<Pred>(pred), void_v)) {
3117  return std::move(*this);
3118  } else {
3119  return none;
3120  }
3121  } else {
3122  if (is_some() && std::invoke(std::forward<Pred>(pred), opt_()[index<1>])) {
3123  return std::move(*this);
3124  } else {
3125  return none;
3126  }
3127  }
3128  }
3129 
3130  /// @brief Converts `option<result<T, E>>` into `result<option<T>, E>`
3131  ///
3132  /// @details
3133  /// If the @ref option is `none`, a @ref result containing a `none` @ref
3134  /// option is returned. If the @ref option contains an ok @ref result,
3135  /// a @ref result containing an ok value of an @ref option with a value
3136  /// is returned. If the @ref option contains a @ref result with an error
3137  /// value, a result with an error value is returned.
3138  ///
3139  /// This function only participates in overload resolution if `T` is a
3140  /// @ref result.
3141  ///
3142  /// ## Example
3143  /// ```
3144  /// option<result<int, std::string>> val1{};
3145  /// option<result<int, std::string>> val2{ok<int>(42)};
3146  /// option<result<int, std::string>> val3{error<std::string>("oh no")};
3147  ///
3148  /// auto val1_trans = val1.transpose();
3149  /// auto val2_trans = val2.transpose();
3150  /// auto val3_trans = val3.transpose();
3151  ///
3152  /// assert(val1_trans.is_ok());
3153  /// assert(val1_trans->is_none());
3154  ///
3155  /// assert(val2_trans.is_ok());
3156  /// assert(val2_trans->is_some());
3157  /// assert(**val2_trans == 42);
3158  ///
3159  /// assert(val3_trans.is_error());
3160  /// assert(val3_trans.error() == "oh no");
3161  /// ```
3162  [[nodiscard]] constexpr auto transpose() const&
3163 #ifndef DOXYGEN
3164  requires(detail::is_result_v<T>)
3165 #endif
3166  {
3167  using ret_t = result<option<typename T::value_type>, typename T::error_type>;
3168  if (is_some()) {
3169  if (opt_()[index<1>].is_ok()) {
3170  return ret_t{in_place, *opt_()[index<1>]};
3171  } else {
3172  return ret_t{in_place_error, opt_()[index<1>].error()};
3173  }
3174  } else {
3175  return ret_t{in_place, none};
3176  }
3177  }
3178 
3179  /// @brief Converts `option<result<T, E>>` into `result<option<T>, E>`
3180  ///
3181  /// @details
3182  /// If the @ref option is `none`, a @ref result containing a `none` @ref
3183  /// option is returned. If the @ref option contains an ok @ref result,
3184  /// a @ref result containing an ok value of an @ref option with a value
3185  /// is returned. If the @ref option contains a @ref result with an error
3186  /// value, a result with an error value is returned.
3187  ///
3188  /// This function only participates in overload resolution if `T` is a
3189  /// @ref result.
3190  ///
3191  /// ## Example
3192  /// ```
3193  /// option<result<int, std::string>> val1{};
3194  /// option<result<int, std::string>> val2{ok<int>(42)};
3195  /// option<result<int, std::string>> val3{error<std::string>("oh no")};
3196  ///
3197  /// auto val1_trans = std::move(val1).transpose();
3198  /// auto val2_trans = std::move(val2).transpose();
3199  /// auto val3_trans = std::move(val3).transpose();
3200  ///
3201  /// assert(val1_trans.is_ok());
3202  /// assert(val1_trans->is_none());
3203  ///
3204  /// assert(val2_trans.is_ok());
3205  /// assert(val2_trans->is_some());
3206  /// assert(**val2_trans == 42);
3207  ///
3208  /// assert(val3_trans.is_error());
3209  /// assert(val3_trans.error() == "oh no");
3210  /// ```
3211  [[nodiscard]] constexpr auto transpose() &&
3212 #ifndef DOXYGEN
3213  requires(detail::is_result_v<T>)
3214 #endif
3215  {
3216  using ret_t = result<option<typename T::value_type>, typename T::error_type>;
3217  if (is_some()) {
3218  if (opt_()[index<1>].is_ok()) {
3219  return ret_t{in_place, *std::move(*this).opt_()[index<1>]};
3220  } else {
3221  return ret_t{in_place_error, std::move(*this).opt_()[index<1>].error()};
3222  }
3223  } else {
3224  return ret_t{in_place, none};
3225  }
3226  }
3227 
3228  /// @brief Calls a visitor callable with the contained value or `void`.
3229  ///
3230  /// @details
3231  /// This function treats an @ref option as if it was a @ref variant of
3232  /// `void` and `T`. If the @ref option contains a value, that value is
3233  /// passed to the visitor. If the @ref option is `none`, the visitor is
3234  /// called with @ref void_t.
3235  ///
3236  /// Note that the @ref overload function can be helpful for defining a
3237  /// visitor inline.
3238  ///
3239  /// ## Example
3240  /// ```cpp
3241  /// option<int> opt1{};
3242  /// option<int> opt2{42};
3243  ///
3244  /// opt1.visit(overload([](int value) {
3245  /// assert(false);
3246  /// }, [](void_t value) {
3247  /// assert(true);
3248  /// });
3249  ///
3250  /// opt2.visit(overload([](int value) {
3251  /// assert(value == 42);
3252  /// }, [](void_t value) {
3253  /// assert(false);
3254  /// });
3255  /// ```
3256  template <typename V>
3257  constexpr
3258 #ifndef DOXYGEN
3259  decltype(auto)
3260 #else
3261  DEDUCED
3262 #endif
3263  visit(V&& visitor) & {
3264  return opt_().visit(std::forward<V>(visitor));
3265  }
3266 
3267  /// @brief Calls a visitor callable with the contained value or `void`.
3268  ///
3269  /// @details
3270  /// This function treats an @ref option as if it was a @ref variant of
3271  /// `void` and `T`. If the @ref option contains a value, that value is
3272  /// passed to the visitor. If the @ref option is `none`, the visitor is
3273  /// called with @ref void_t.
3274  ///
3275  /// Note that the @ref overload function can be helpful for defining a
3276  /// visitor inline.
3277  ///
3278  /// ## Example
3279  /// ```cpp
3280  /// const option<int> opt1{};
3281  /// const option<int> opt2{42};
3282  ///
3283  /// opt1.visit(overload([](int value) {
3284  /// assert(false);
3285  /// }, [](void_t value) {
3286  /// assert(true);
3287  /// });
3288  ///
3289  /// opt2.visit(overload([](int value) {
3290  /// assert(value == 42);
3291  /// }, [](void_t value) {
3292  /// assert(false);
3293  /// });
3294  /// ```
3295  template <typename V>
3296  constexpr
3297 #ifndef DOXYGEN
3298  decltype(auto)
3299 #else
3300  DEDUCED
3301 #endif
3302  visit(V&& visitor) const& {
3303  return opt_().visit(std::forward<V>(visitor));
3304  }
3305 
3306  /// @brief Calls a visitor callable with the contained value or `void`.
3307  ///
3308  /// @details
3309  /// This function treats an @ref option as if it was a @ref variant of
3310  /// `void` and `T`. If the @ref option contains a value, that value is
3311  /// passed to the visitor. If the @ref option is `none`, the visitor is
3312  /// called without any arguments.
3313  ///
3314  /// Note that the @ref overload function can be helpful for defining a
3315  /// visitor inline.
3316  ///
3317  /// ## Example
3318  /// ```cpp
3319  /// option<int> opt1{};
3320  /// option<int> opt2{42};
3321  ///
3322  /// std::move(opt1).visit(overload([](int value) {
3323  /// assert(false);
3324  /// }, [](void_t value) {
3325  /// assert(true);
3326  /// });
3327  ///
3328  /// std::move(opt2).visit(overload([](int value) {
3329  /// assert(value == 42);
3330  /// }, [](void_t value) {
3331  /// assert(false);
3332  /// });
3333  /// ```
3334  template <typename V>
3335  constexpr
3336 #ifndef DOXYGEN
3337  decltype(auto)
3338 #else
3339  DEDUCED
3340 #endif
3341  visit(V&& visitor) && {
3342  return std::move(*this).opt_().visit(std::forward<V>(visitor));
3343  }
3344 
3345  /// @brief Calls a visitor callable with the contained value or `void`.
3346  ///
3347  /// @details
3348  /// This function treats an @ref option as if it was a @ref variant of
3349  /// `void` and `T`. If the @ref option contains a value, that value is
3350  /// passed to the visitor. If the @ref option is `none`, the visitor is
3351  /// called with @ref void_t.
3352  ///
3353  /// Note that the @ref overload function can be helpful for defining a
3354  /// visitor inline.
3355  ///
3356  /// ## Example
3357  /// ```cpp
3358  /// const option<int> opt1{};
3359  /// const option<int> opt2{42};
3360  ///
3361  /// std::move(opt1).visit(overload([](int value) {
3362  /// assert(false);
3363  /// }, [](void_t value) {
3364  /// assert(true);
3365  /// });
3366  ///
3367  /// std::move(opt2).visit(overload([](int value) {
3368  /// assert(value == 42);
3369  /// }, [](void_t value) {
3370  /// assert(false);
3371  /// });
3372  /// ```
3373  template <typename V>
3374  constexpr
3375 #ifndef DOXYGEN
3376  decltype(auto)
3377 #else
3378  DEDUCED
3379 #endif
3380  visit(V&& visitor) const&& {
3381  return std::move(*this).opt_().visit(std::forward<V>(visitor));
3382  }
3383 
3384  /// @brief Calls a visitor callable with the contained value and meta data.
3385  ///
3386  /// @details
3387  /// This function treats an @ref option as if it was a @ref variant of
3388  /// `void` and `T`. If the @ref option contains a value, that value is
3389  /// passed to the visitor. If the @ref option is `none`, the visitor is
3390  /// called with @ref void_t.
3391  ///
3392  /// In either case, an additional (second) parameter is passed to the
3393  /// visitor, which provides `constexpr` information about the specific
3394  /// alternative being visited. This `info` parameter has the API shown
3395  /// below. Note that this type is always an empty type.
3396  ///
3397  /// ```
3398  /// struct alternative_info {
3399  /// // index of the alternative in the source variant
3400  /// static inline constexpr size_t index = ...;
3401  ///
3402  /// // type of the alternative as declared in the source variant
3403  /// using type = ...;
3404  ///
3405  /// // helper function for forwarding non-const alternative values
3406  /// // without needing to provide a template argument.
3407  /// static constexpr decltype(auto) forward(...);
3408  /// };
3409  /// ```
3410  ///
3411  /// Note that the @ref overload function can be helpful for defining a
3412  /// visitor inline.
3413  ///
3414  /// ## Example
3415  /// ```cpp
3416  /// option<int> opt1{};
3417  /// option<int> opt2{42};
3418  ///
3419  /// opt1.visit_informed([](auto value, auto info) {
3420  /// if constexpr (info.index == 0) { // none
3421  /// assert(true);
3422  /// } else if constexpr (info.index == 1) { // some
3423  /// assert(false);
3424  /// }
3425  /// });
3426  ///
3427  /// opt1.visit_informed([](auto value, auto info) {
3428  /// if constexpr (info.index == 0) { // none
3429  /// assert(false);
3430  /// } else if constexpr (info.index == 1) { // some
3431  /// assert(value == 42);
3432  /// }
3433  /// });
3434  /// ```
3435  template <typename V>
3436  constexpr
3437 #ifndef DOXYGEN
3438  decltype(auto)
3439 #else
3440  DEDUCED
3441 #endif
3442  visit_informed(V&& visitor) & {
3443  return opt_().visit(std::forward<V>(visitor));
3444  }
3445 
3446  /// @brief Calls a visitor callable with the contained value and meta data.
3447  ///
3448  /// @details
3449  /// This function treats an @ref option as if it was a @ref variant of
3450  /// `void` and `T`. If the @ref option contains a value, that value is
3451  /// passed to the visitor. If the @ref option is `none`, the visitor is
3452  /// called with @ref void_t.
3453  ///
3454  /// In either case, an additional (second) parameter is passed to the
3455  /// visitor, which provides `constexpr` information about the specific
3456  /// alternative being visited. This `info` parameter has the API shown
3457  /// below. Note that this type is always an empty type.
3458  ///
3459  /// ```
3460  /// struct alternative_info {
3461  /// // index of the alternative in the source variant
3462  /// static inline constexpr size_t index = ...;
3463  ///
3464  /// // type of the alternative as declared in the source variant
3465  /// using type = ...;
3466  ///
3467  /// // helper function for forwarding non-const alternative values
3468  /// // without needing to provide a template argument.
3469  /// static constexpr decltype(auto) forward(...);
3470  /// };
3471  /// ```
3472  ///
3473  /// Note that the @ref overload function can be helpful for defining a
3474  /// visitor inline.
3475  ///
3476  /// ## Example
3477  /// ```cpp
3478  /// const option<int> opt1{};
3479  /// const option<int> opt2{42};
3480  ///
3481  /// opt1.visit_informed([](auto value, auto info) {
3482  /// if constexpr (info.index == 0) { // none
3483  /// assert(true);
3484  /// } else if constexpr (info.index == 1) { // some
3485  /// assert(false);
3486  /// }
3487  /// });
3488  ///
3489  /// opt1.visit_informed([](auto value, auto info) {
3490  /// if constexpr (info.index == 0) { // none
3491  /// assert(false);
3492  /// } else if constexpr (info.index == 1) { // some
3493  /// assert(value == 42);
3494  /// }
3495  /// });
3496  /// ```
3497  template <typename V>
3498  constexpr
3499 #ifndef DOXYGEN
3500  decltype(auto)
3501 #else
3502  DEDUCED
3503 #endif
3504  visit_informed(V&& visitor) const& {
3505  return opt_().visit(std::forward<V>(visitor));
3506  }
3507 
3508  /// @brief Calls a visitor callable with the contained value and meta data.
3509  ///
3510  /// @details
3511  /// This function treats an @ref option as if it was a @ref variant of
3512  /// `void` and `T`. If the @ref option contains a value, that value is
3513  /// passed to the visitor. If the @ref option is `none`, the visitor is
3514  /// called with @ref void_t.
3515  ///
3516  /// In either case, an additional (second) parameter is passed to the
3517  /// visitor, which provides `constexpr` information about the specific
3518  /// alternative being visited. This `info` parameter has the API shown
3519  /// below. Note that this type is always an empty type.
3520  ///
3521  /// ```
3522  /// struct alternative_info {
3523  /// // index of the alternative in the source variant
3524  /// static inline constexpr size_t index = ...;
3525  ///
3526  /// // type of the alternative as declared in the source variant
3527  /// using type = ...;
3528  ///
3529  /// // helper function for forwarding non-const alternative values
3530  /// // without needing to provide a template argument.
3531  /// static constexpr decltype(auto) forward(...);
3532  /// };
3533  /// ```
3534  ///
3535  /// Note that the @ref overload function can be helpful for defining a
3536  /// visitor inline.
3537  ///
3538  /// ## Example
3539  /// ```cpp
3540  /// option<int> opt1{};
3541  /// option<int> opt2{42};
3542  ///
3543  /// std::move(opt1).visit_informed([](auto value, auto info) {
3544  /// if constexpr (info.index == 0) { // none
3545  /// assert(true);
3546  /// } else if constexpr (info.index == 1) { // some
3547  /// assert(false);
3548  /// }
3549  /// });
3550  ///
3551  /// std::move(opt1).visit_informed([](auto value, auto info) {
3552  /// if constexpr (info.index == 0) { // none
3553  /// assert(false);
3554  /// } else if constexpr (info.index == 1) { // some
3555  /// assert(value == 42);
3556  /// }
3557  /// });
3558  /// ```
3559  template <typename V>
3560  constexpr
3561 #ifndef DOXYGEN
3562  decltype(auto)
3563 #else
3564  DEDUCED
3565 #endif
3566  visit_informed(V&& visitor) && {
3567  return std::move(*this).opt_().visit(std::forward<V>(visitor));
3568  }
3569 
3570  /// @brief Calls a visitor callable with the contained value and meta data.
3571  ///
3572  /// @details
3573  /// This function treats an @ref option as if it was a @ref variant of
3574  /// `void` and `T`. If the @ref option contains a value, that value is
3575  /// passed to the visitor. If the @ref option is `none`, the visitor is
3576  /// called with @ref void_t.
3577  ///
3578  /// In either case, an additional (second) parameter is passed to the
3579  /// visitor, which provides `constexpr` information about the specific
3580  /// alternative being visited. This `info` parameter has the API shown
3581  /// below. Note that this type is always an empty type.
3582  ///
3583  /// ```
3584  /// struct alternative_info {
3585  /// // index of the alternative in the source variant
3586  /// static inline constexpr size_t index = ...;
3587  ///
3588  /// // type of the alternative as declared in the source variant
3589  /// using type = ...;
3590  ///
3591  /// // helper function for forwarding non-const alternative values
3592  /// // without needing to provide a template argument.
3593  /// static constexpr decltype(auto) forward(...);
3594  /// };
3595  /// ```
3596  ///
3597  /// Note that the @ref overload function can be helpful for defining a
3598  /// visitor inline.
3599  ///
3600  /// ## Example
3601  /// ```cpp
3602  /// const option<int> opt1{};
3603  /// const option<int> opt2{42};
3604  ///
3605  /// std::move(opt1).visit_informed([](auto value, auto info) {
3606  /// if constexpr (info.index == 0) { // none
3607  /// assert(true);
3608  /// } else if constexpr (info.index == 1) { // some
3609  /// assert(false);
3610  /// }
3611  /// });
3612  ///
3613  /// std::move(opt1).visit_informed([](auto value, auto info) {
3614  /// if constexpr (info.index == 0) { // none
3615  /// assert(false);
3616  /// } else if constexpr (info.index == 1) { // some
3617  /// assert(value == 42);
3618  /// }
3619  /// });
3620  /// ```
3621  template <typename V>
3622  constexpr
3623 #ifndef DOXYGEN
3624  decltype(auto)
3625 #else
3626  DEDUCED
3627 #endif
3628  visit_informed(V&& visitor) const&& {
3629  return std::move(*this).opt_().visit(std::forward<V>(visitor));
3630  }
3631 
3632  /// @brief Swaps two @ref option instances
3633  ///
3634  /// @details
3635  /// If both @ref option instances contain a value, the two contained values
3636  /// are swapped directly. Otherwise, if one @ref option contains a value,
3637  /// that value is move constructed into the other @ref option, and the old
3638  /// value is destroyed in place. If both @ref option instances are `none`,
3639  /// nothing is done.
3640  ///
3641  /// This function is `noexcept` if the contained value type is nothrow
3642  /// swappable.
3643  ///
3644  /// ## Example
3645  /// ```
3646  /// option<int> opt1{};
3647  /// option<int> opt2{42};
3648  ///
3649  /// opt1.swap(opt2);
3650  ///
3651  /// assert(opt1.has_value());
3652  /// assert(*opt1 == 42);
3653  ///
3654  /// assert(!opt1.has_value());
3655  /// ```
3656  constexpr void swap(option& other)
3657 #ifndef DOXYGEN
3658  noexcept(noexcept(opt_().swap(other.opt_())))
3659 #else
3661 #endif
3662  {
3663  opt_().swap(other.opt_());
3664  }
3665 
3666  /// @brief Sets the @ref option to `none`.
3667  ///
3668  /// @details
3669  /// If the @ref option contains a value, the value is destroyed in place.
3670  /// Otherwise, nothing is done.
3671  ///
3672  /// ## Example
3673  /// ```
3674  /// option<int> opt1{};
3675  /// option<int> opt2{42};
3676  ///
3677  /// opt1.reset();
3678  /// opt2.reset();
3679  ///
3680  /// assert(!opt1.has_value());
3681  /// assert(!opt2.has_value());
3682  /// ```
3683  constexpr void reset() noexcept { opt_().template emplace<0>(); }
3684 
3685  /// @brief Constructs a new value in place into the @ref option.
3686  ///
3687  /// @details
3688  /// If the @ref option already contains a value, the old value is first
3689  /// destroyed in place. In any case, a new value is constructed in place
3690  /// in the @ref option.
3691  ///
3692  /// ## Example
3693  /// ```
3694  /// option<std::string> opt1{};
3695  /// option<std::string> opt2{"hello"};
3696  ///
3697  /// opt1.emplace(5, 'a');
3698  /// opt2.emplace(5, 'a');
3699  ///
3700  /// assert(opt1.has_value());
3701  /// assert(*opt1 == "aaaaa");
3702  ///
3703  /// assert(opt2.has_value());
3704  /// assert(*opt2 == "aaaaa");
3705  /// ```
3706  template <typename... Args>
3707  constexpr reference emplace(Args&&... args) {
3708  opt_().template emplace<1>(std::forward<Args>(args)...);
3709  return opt_()[index<1>];
3710  }
3711 };
3712 
3713 /// @relates option
3714 /// @brief Gets an @ref option value by index, as if it were a @ref variant.
3715 ///
3716 /// @details
3717 /// This function is provided to make @ref option generically compatible with
3718 /// @ref variant. This function treats `option<T>` as if it were
3719 /// `variant<void, T>`, where index 0 gets `void` (which represents `none`)
3720 /// and index 1 gets `T` (which is the contained value).
3721 ///
3722 /// ## Example
3723 /// ```
3724 /// option<int> opt{42};
3725 ///
3726 /// assert(get<1>(opt) == 42);
3727 /// ```
3728 ///
3729 /// @tparam IDX The "alternative" index
3730 ///
3731 /// @param opt The @ref option to access
3732 ///
3733 /// @return A reference to the accessed "alternative"
3734 ///
3735 /// @throws bad_option_access Thrown if the @ref option state does not match
3736 /// the index `IDX`.
3737 template <size_t IDX, typename T>
3738 constexpr
3739 #ifndef DOXYGEN
3740  typename detail::traits<detail::select_t<IDX, void, T>>::reference
3741 #else
3742  REFERENCE
3743 #endif
3744  get(option<T>& opt) {
3745  if constexpr (IDX == 0) {
3746  if (opt.has_value()) { throw bad_option_access(); }
3747  } else {
3748  static_assert(IDX == 1, "Invalid get index for sumty::option");
3749  return opt.value();
3750  }
3751 }
3752 
3753 /// @relates option
3754 /// @brief Gets an @ref option value by index, as if it were a @ref variant.
3755 ///
3756 /// @details
3757 /// This function is provided to make @ref option generically compatible with
3758 /// @ref variant. This function treats `option<T>` as if it were
3759 /// `variant<void, T>`, where index 0 gets `void` (which represents `none`)
3760 /// and index 1 gets `T` (which is the contained value).
3761 ///
3762 /// ## Example
3763 /// ```
3764 /// const option<int> opt{42};
3765 ///
3766 /// assert(get<1>(opt) == 42);
3767 /// ```
3768 ///
3769 /// @tparam IDX The "alternative" index
3770 ///
3771 /// @param opt The @ref option to access
3772 ///
3773 /// @return A const reference to the accessed "alternative"
3774 ///
3775 /// @throws bad_option_access Thrown if the @ref option state does not match
3776 /// the index `IDX`.
3777 template <size_t IDX, typename T>
3778 constexpr
3779 #ifndef DOXYGEN
3780  typename detail::traits<detail::select_t<IDX, void, T>>::const_reference
3781 #else
3783 #endif
3784  get(const option<T>& opt) {
3785  if constexpr (IDX == 0) {
3786  if (opt.has_value()) { throw bad_option_access(); }
3787  } else {
3788  static_assert(IDX == 1, "Invalid get index for sumty::option");
3789  return opt.value();
3790  }
3791 }
3792 
3793 /// @relates option
3794 /// @brief Gets an @ref option value by index, as if it were a @ref variant.
3795 ///
3796 /// @details
3797 /// This function is provided to make @ref option generically compatible with
3798 /// @ref variant. This function treats `option<T>` as if it were
3799 /// `variant<void, T>`, where index 0 gets `void` (which represents `none`)
3800 /// and index 1 gets `T` (which is the contained value).
3801 ///
3802 /// ## Example
3803 /// ```
3804 /// option<int> opt{42};
3805 ///
3806 /// assert(get<1>(std::move(opt)) == 42);
3807 /// ```
3808 ///
3809 /// @tparam IDX The "alternative" index
3810 ///
3811 /// @param opt The @ref option to access
3812 ///
3813 /// @return An rvalue reference to the accessed "alternative"
3814 ///
3815 /// @throws bad_option_access Thrown if the @ref option state does not match
3816 /// the index `IDX`.
3817 template <size_t IDX, typename T>
3818 constexpr
3819 #ifndef DOXYGEN
3820  typename detail::traits<detail::select_t<IDX, void, T>>::rvalue_reference
3821 #else
3823 #endif
3824  get(option<T>&& opt) {
3825  if constexpr (IDX == 0) {
3826  if (opt.has_value()) { throw bad_option_access(); }
3827  } else {
3828  static_assert(IDX == 1, "Invalid get index for sumty::option");
3829  return std::move(opt).value();
3830  }
3831 }
3832 
3833 /// @relates option
3834 /// @brief Gets an @ref option value by index, as if it were a @ref variant.
3835 ///
3836 /// @details
3837 /// This function is provided to make @ref option generically compatible with
3838 /// @ref variant. This function treats `option<T>` as if it were
3839 /// `variant<void, T>`, where index 0 gets `void` (which represents `none`)
3840 /// and index 1 gets `T` (which is the contained value).
3841 ///
3842 /// ## Example
3843 /// ```
3844 /// const option<int> opt{42};
3845 ///
3846 /// assert(get<1>(std::move(opt)) == 42);
3847 /// ```
3848 ///
3849 /// @tparam IDX The "alternative" index
3850 ///
3851 /// @param opt The @ref option to access
3852 ///
3853 /// @return A const rvalue reference to the accessed "alternative"
3854 ///
3855 /// @throws bad_option_access Thrown if the @ref option state does not match
3856 /// the index `IDX`.
3857 template <size_t IDX, typename T>
3858 constexpr
3859 #ifndef DOXYGEN
3860  typename detail::traits<detail::select_t<IDX, void, T>>::const_rvalue_reference
3861 #else
3863 #endif
3864  get(const option<T>&& opt) {
3865  if constexpr (IDX == 0) {
3866  if (opt.has_value()) { throw bad_option_access(); }
3867  } else {
3868  static_assert(IDX == 1, "Invalid get index for sumty::option");
3869  return std::move(opt).value();
3870  }
3871 }
3872 
3873 /// @relates option
3874 /// @brief Gets an @ref option value by type, as if it were a @ref variant.
3875 ///
3876 /// @details
3877 /// This function is provided to make @ref option generically compatible with
3878 /// @ref variant. This function treats `option<T>` as if it were
3879 /// `variant<void, T>`, where `void` is the `none` alternative, and `T` is
3880 /// the alternative with a value.
3881 ///
3882 /// This function only participates in overload resolution if the contained
3883 /// value of the @ref option is not `void`.
3884 ///
3885 /// ## Example
3886 /// ```
3887 /// option<int> opt{42};
3888 ///
3889 /// assert(get<int>(opt) == 42);
3890 /// ```
3891 ///
3892 /// @tparam T The type of the alternative to access
3893 ///
3894 /// @param opt The @ref option to access
3895 ///
3896 /// @return A reference to the accessed alternative
3897 ///
3898 /// @throws bad_option_access Thrown if the @ref option does not contain the
3899 /// requested type `T`.
3900 template <typename T, typename U>
3901 #ifndef DOXYGEN
3902  requires(!std::is_void_v<U>)
3903 #endif
3904 constexpr
3905 #ifndef DOXYGEN
3906  typename detail::traits<T>::reference
3907 #else
3908  REFERENCE
3909 #endif
3910  get(option<U>& opt) {
3911  if constexpr (std::is_void_v<T>) {
3912  if (opt.has_value()) { throw bad_option_access(); }
3913  } else {
3914  static_assert(std::is_same_v<T, U>, "Invalid get type for sumty::option");
3915  return opt.value();
3916  }
3917 }
3918 
3919 /// @relates option
3920 /// @brief Gets an @ref option value by type, as if it were a @ref variant.
3921 ///
3922 /// @details
3923 /// This function is provided to make @ref option generically compatible with
3924 /// @ref variant. This function treats `option<T>` as if it were
3925 /// `variant<void, T>`, where `void` is the `none` alternative, and `T` is
3926 /// the alternative with a value.
3927 ///
3928 /// This function only participates in overload resolution if the contained
3929 /// value of the @ref option is not `void`.
3930 ///
3931 /// ## Example
3932 /// ```
3933 /// const option<int> opt{42};
3934 ///
3935 /// assert(get<int>(opt) == 42);
3936 /// ```
3937 ///
3938 /// @tparam T The type of the alternative to access
3939 ///
3940 /// @param opt The @ref option to access
3941 ///
3942 /// @return A const reference to the accessed alternative
3943 ///
3944 /// @throws bad_option_access Thrown if the @ref option does not contain the
3945 /// requested type `T`.
3946 template <typename T, typename U>
3947 #ifndef DOXYGEN
3948  requires(!std::is_void_v<U>)
3949 #endif
3950 constexpr
3951 #ifndef DOXYGEN
3952  typename detail::traits<T>::const_reference
3953 #else
3955 #endif
3956  get(const option<U>& opt) {
3957  if constexpr (std::is_void_v<T>) {
3958  if (opt.has_value()) { throw bad_option_access(); }
3959  } else {
3960  static_assert(std::is_same_v<T, U>, "Invalid get type for sumty::option");
3961  return opt.value();
3962  }
3963 }
3964 
3965 /// @relates option
3966 /// @brief Gets an @ref option value by type, as if it were a @ref variant.
3967 ///
3968 /// @details
3969 /// This function is provided to make @ref option generically compatible with
3970 /// @ref variant. This function treats `option<T>` as if it were
3971 /// `variant<void, T>`, where `void` is the `none` alternative, and `T` is
3972 /// the alternative with a value.
3973 ///
3974 /// This function only participates in overload resolution if the contained
3975 /// value of the @ref option is not `void`.
3976 ///
3977 /// ## Example
3978 /// ```
3979 /// option<int> opt{42};
3980 ///
3981 /// assert(get<int>(std::move(opt)) == 42);
3982 /// ```
3983 ///
3984 /// @tparam T The type of the alternative to access
3985 ///
3986 /// @param opt The @ref option to access
3987 ///
3988 /// @return An rvalue reference to the accessed alternative
3989 ///
3990 /// @throws bad_option_access Thrown if the @ref option does not contain the
3991 /// requested type `T`.
3992 template <typename T, typename U>
3993 #ifndef DOXYGEN
3994  requires(!std::is_void_v<U>)
3995 #endif
3996 constexpr
3997 #ifndef DOXYGEN
3998  typename detail::traits<T>::rvalue_reference
3999 #else
4001 #endif
4002  get(option<U>&& opt) {
4003  if constexpr (std::is_void_v<T>) {
4004  if (opt.has_value()) { throw bad_option_access(); }
4005  } else {
4006  static_assert(std::is_same_v<T, U>, "Invalid get type for sumty::option");
4007  return std::move(opt).value();
4008  }
4009 }
4010 
4011 /// @relates option
4012 /// @brief Gets an @ref option value by type, as if it were a @ref variant.
4013 ///
4014 /// @details
4015 /// This function is provided to make @ref option generically compatible with
4016 /// @ref variant. This function treats `option<T>` as if it were
4017 /// `variant<void, T>`, where `void` is the `none` alternative, and `T` is
4018 /// the alternative with a value.
4019 ///
4020 /// This function only participates in overload resolution if the contained
4021 /// value of the @ref option is not `void`.
4022 ///
4023 /// ## Example
4024 /// ```
4025 /// const option<int> opt{42};
4026 ///
4027 /// assert(get<int>(std::move(opt)) == 42);
4028 /// ```
4029 ///
4030 /// @tparam T The type of the alternative to access
4031 ///
4032 /// @param opt The @ref option to access
4033 ///
4034 /// @return A const rvalue reference to the accessed alternative
4035 ///
4036 /// @throws bad_option_access Thrown if the @ref option does not contain the
4037 /// requested type `T`.
4038 template <typename T, typename U>
4039 #ifndef DOXYGEN
4040  requires(!std::is_void_v<U>)
4041 #endif
4042 constexpr
4043 #ifndef DOXYGEN
4044  typename detail::traits<T>::const_rvalue_reference
4045 #else
4047 #endif
4048  get(const option<U>&& opt) {
4049  if constexpr (std::is_void_v<T>) {
4050  if (opt.has_value()) { throw bad_option_access(); }
4051  } else {
4052  static_assert(std::is_same_v<T, U>, "Invalid get type for sumty::option");
4053  return std::move(opt).value();
4054  }
4055 }
4056 
4057 /// @relates option
4058 /// @brief Tests two @ref option instances for equality.
4059 ///
4060 /// @details
4061 /// ## Example
4062 /// ```
4063 /// option<int> opt1{};
4064 /// option<int> opt2{42};
4065 /// option<int> opt3{24};
4066 ///
4067 /// assert(opt1 == opt1);
4068 /// assert(opt2 == opt2);
4069 /// assert(!(opt1 == opt2));
4070 /// assert(!(opt2 == opt3));
4071 /// ```
4072 template <typename T, typename U>
4073 constexpr bool operator==(const option<T>& lhs, const option<U>& rhs) {
4074  if (lhs.has_value()) {
4075  return rhs.has_value() && *lhs == *rhs;
4076  } else {
4077  return !rhs.has_value();
4078  }
4079 }
4080 
4081 /// @relates option
4082 /// @brief Tests two @ref option instances for inequality.
4083 ///
4084 /// @details
4085 /// ## Example
4086 /// ```
4087 /// option<int> opt1{};
4088 /// option<int> opt2{42};
4089 /// option<int> opt3{24};
4090 ///
4091 /// assert(!(opt1 != opt1));
4092 /// assert(!(opt2 != opt2));
4093 /// assert(opt1 != opt2);
4094 /// assert(opt2 != opt3);
4095 /// ```
4096 template <typename T, typename U>
4097 constexpr bool operator!=(const option<T>& lhs, const option<U>& rhs) {
4098  if (lhs.has_value()) {
4099  return !rhs.has_value() || *lhs != *rhs;
4100  } else {
4101  return rhs.has_value();
4102  }
4103 }
4104 
4105 /// @relates option
4106 /// @brief Compares two @ref option instances.
4107 ///
4108 /// @details
4109 /// `none` is always less than any contained value.
4110 ///
4111 /// ## Example
4112 /// ```
4113 /// option<int> opt1{};
4114 /// option<int> opt2{42};
4115 /// option<int> opt3{24};
4116 ///
4117 /// assert(opt1 < opt2);
4118 /// assert(opt1 < opt3);
4119 /// assert(opt3 < opt2);
4120 /// ```
4121 template <typename T, typename U>
4122 constexpr bool operator<(const option<T>& lhs, const option<U>& rhs) {
4123  return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs);
4124 }
4125 
4126 /// @relates option
4127 /// @brief Compares two @ref option instances.
4128 ///
4129 /// @details
4130 /// `none` is always less than any contained value.
4131 ///
4132 /// ## Example
4133 /// ```
4134 /// option<int> opt1{};
4135 /// option<int> opt2{42};
4136 /// option<int> opt3{24};
4137 ///
4138 /// assert(opt2 > opt1);
4139 /// assert(opt3 > opt1);
4140 /// assert(opt2 > opt3);
4141 /// ```
4142 template <typename T, typename U>
4143 constexpr bool operator>(const option<T>& lhs, const option<U>& rhs) {
4144  return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs);
4145 }
4146 
4147 /// @relates option
4148 /// @brief Compares two @ref option instances.
4149 ///
4150 /// @details
4151 /// `none` is always less than any contained value.
4152 ///
4153 /// ## Example
4154 /// ```
4155 /// option<int> opt1{};
4156 /// option<int> opt2{42};
4157 /// option<int> opt3{24};
4158 ///
4159 /// assert(opt1 <= opt2);
4160 /// assert(opt1 <= opt3);
4161 /// assert(opt3 <= opt2);
4162 /// assert(opt2 <= opt2);
4163 /// ```
4164 template <typename T, typename U>
4165 constexpr bool operator<=(const option<T>& lhs, const option<U>& rhs) {
4166  return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs);
4167 }
4168 
4169 /// @relates option
4170 /// @brief Compares two @ref option instances.
4171 ///
4172 /// @details
4173 /// `none` is always less than any contained value.
4174 ///
4175 /// ## Example
4176 /// ```
4177 /// option<int> opt1{};
4178 /// option<int> opt2{42};
4179 /// option<int> opt3{24};
4180 ///
4181 /// assert(opt2 >= opt1);
4182 /// assert(opt3 >= opt1);
4183 /// assert(opt2 >= opt3);
4184 /// assert(opt2 >= opt2);
4185 /// ```
4186 template <typename T, typename U>
4187 constexpr bool operator>=(const option<T>& lhs, const option<U>& rhs) {
4188  return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs);
4189 }
4190 
4191 /// @relates option
4192 /// @brief Compares two @ref option instances.
4193 ///
4194 /// @details
4195 /// `none` is always less than any contained value.
4196 ///
4197 /// ## Example
4198 /// ```
4199 /// option<int> opt1{};
4200 /// option<int> opt2{42};
4201 /// option<int> opt3{24};
4202 ///
4203 /// assert((opt1 <=> opt2) == std::strong_ordering::less);
4204 /// assert((opt1 <=> opt3) == std::strong_ordering::less);
4205 /// assert((opt2 <=> opt3) == std::strong_ordering::greater);
4206 /// assert((opt2 <=> opt2) == std::strong_ordering::equal);
4207 /// ```
4208 template <typename T, typename U>
4209 #ifndef DOXYGEN
4211 #endif
4212 constexpr
4213 #ifndef DOXYGEN
4214  std::compare_three_way_result_t<std::remove_cvref_t<T>, std::remove_cvref_t<U>>
4215 #else
4216  auto
4217 #endif
4218  operator<=>(const option<T>& lhs, const option<U>& rhs) {
4219  if (lhs.has_value() && rhs.has_value()) {
4220  return *lhs <=> *rhs;
4221  } else {
4222  return lhs.has_value() <=> rhs.has_value();
4223  }
4224 }
4225 
4226 /// @relates option
4227 /// @brief Compares an @ref option with a value.
4228 ///
4229 /// @details
4230 /// `none` is always less than the value. If not `none`, the contained value
4231 /// is compared with the value.
4232 ///
4233 /// ## Example
4234 /// ```
4235 /// option<int> opt1{};
4236 /// option<int> opt2{42};
4237 ///
4238 /// assert(!(opt1 == 42));
4239 /// assert(opt2 == 42);
4240 /// assert(!(opt2 == 24));
4241 /// ```
4242 template <typename T, typename U>
4243 constexpr bool operator==(const option<T>& lhs, const U& rhs) {
4244  return lhs.has_value() && *lhs == rhs;
4245 }
4246 
4247 /// @relates option
4248 /// @brief Compares an @ref option with a value.
4249 ///
4250 /// @details
4251 /// `none` is always less than the value. If not `none`, the contained value
4252 /// is compared with the value.
4253 ///
4254 /// ## Example
4255 /// ```
4256 /// option<int> opt1{};
4257 /// option<int> opt2{42};
4258 ///
4259 /// assert(!(42 == opt1));
4260 /// assert(42 == opt2);
4261 /// assert(!(24 == opt2));
4262 /// ```
4263 template <typename T, typename U>
4264 constexpr bool operator==(const U& lhs, const option<T>& rhs) {
4265  return rhs.has_value() && lhs == *rhs;
4266 }
4267 
4268 /// @relates option
4269 /// @brief Compares an @ref option with a value.
4270 ///
4271 /// @details
4272 /// `none` is always less than the value. If not `none`, the contained value
4273 /// is compared with the value.
4274 ///
4275 /// ## Example
4276 /// ```
4277 /// option<int> opt1{};
4278 /// option<int> opt2{42};
4279 ///
4280 /// assert(opt1 != 42);
4281 /// assert(!(opt2 != 42));
4282 /// assert(opt2 != 24);
4283 /// ```
4284 template <typename T, typename U>
4285 constexpr bool operator!=(const option<T>& lhs, const U& rhs) {
4286  return !lhs.has_value() || *lhs != rhs;
4287 }
4288 
4289 /// @relates option
4290 /// @brief Compares an @ref option with a value.
4291 ///
4292 /// @details
4293 /// `none` is always less than the value. If not `none`, the contained value
4294 /// is compared with the value.
4295 ///
4296 /// ## Example
4297 /// ```
4298 /// option<int> opt1{};
4299 /// option<int> opt2{42};
4300 ///
4301 /// assert(42 != opt1);
4302 /// assert(!(42 != opt2));
4303 /// assert(24 != opt2);
4304 /// ```
4305 template <typename T, typename U>
4306 constexpr bool operator!=(const U& lhs, const option<T>& rhs) {
4307  return !rhs.has_value() || lhs != *rhs;
4308 }
4309 
4310 /// @relates option
4311 /// @brief Compares an @ref option with a value.
4312 ///
4313 /// @details
4314 /// `none` is always less than the value. If not `none`, the contained value
4315 /// is compared with the value.
4316 ///
4317 /// ## Example
4318 /// ```
4319 /// option<int> opt1{};
4320 /// option<int> opt2{42};
4321 ///
4322 /// assert(opt1 < 42);
4323 /// assert(!(opt2 < 42));
4324 /// assert(opt2 < 100);
4325 /// ```
4326 template <typename T, typename U>
4327 constexpr bool operator<(const option<T>& lhs, const U& rhs) {
4328  return !lhs.has_value() || *lhs < rhs;
4329 }
4330 
4331 /// @relates option
4332 /// @brief Compares an @ref option with a value.
4333 ///
4334 /// @details
4335 /// `none` is always less than the value. If not `none`, the contained value
4336 /// is compared with the value.
4337 ///
4338 /// ## Example
4339 /// ```
4340 /// option<int> opt1{};
4341 /// option<int> opt2{42};
4342 ///
4343 /// assert(!(42 < opt1));
4344 /// assert(!(42 < opt2));
4345 /// assert(40 < opt2);
4346 /// ```
4347 template <typename T, typename U>
4348 constexpr bool operator<(const U& lhs, const option<T>& rhs) {
4349  return rhs.has_value() && lhs < *rhs;
4350 }
4351 
4352 /// @relates option
4353 /// @brief Compares an @ref option with a value.
4354 ///
4355 /// @details
4356 /// `none` is always less than the value. If not `none`, the contained value
4357 /// is compared with the value.
4358 ///
4359 /// ## Example
4360 /// ```
4361 /// option<int> opt1{};
4362 /// option<int> opt2{42};
4363 ///
4364 /// assert(!(opt1 > 42));
4365 /// assert(!(opt2 > 42));
4366 /// assert(opt2 > 40);
4367 /// ```
4368 template <typename T, typename U>
4369 constexpr bool operator>(const option<T>& lhs, const U& rhs) {
4370  return !lhs.has_value() && *lhs > rhs;
4371 }
4372 
4373 /// @relates option
4374 /// @brief Compares an @ref option with a value.
4375 ///
4376 /// @details
4377 /// `none` is always less than the value. If not `none`, the contained value
4378 /// is compared with the value.
4379 ///
4380 /// ## Example
4381 /// ```
4382 /// option<int> opt1{};
4383 /// option<int> opt2{42};
4384 ///
4385 /// assert(42 > opt);
4386 /// assert(!(42 > opt2));
4387 /// assert(100 > opt2);
4388 /// ```
4389 template <typename T, typename U>
4390 constexpr bool operator>(const U& lhs, const option<T>& rhs) {
4391  return !rhs.has_value() || lhs > *lhs;
4392 }
4393 
4394 /// @relates option
4395 /// @brief Compares an @ref option with a value.
4396 ///
4397 /// @details
4398 /// `none` is always less than the value. If not `none`, the contained value
4399 /// is compared with the value.
4400 ///
4401 /// ## Example
4402 /// ```
4403 /// option<int> opt1{};
4404 /// option<int> opt2{42};
4405 ///
4406 /// assert(opt1 <= 42);
4407 /// assert(opt2 <= 42);
4408 /// assert(!(opt2 <= 100));
4409 /// ```
4410 template <typename T, typename U>
4411 constexpr bool operator<=(const option<T>& lhs, const U& rhs) {
4412  return !lhs.has_value() || *lhs <= rhs;
4413 }
4414 
4415 /// @relates option
4416 /// @brief Compares an @ref option with a value.
4417 ///
4418 /// @details
4419 /// `none` is always less than the value. If not `none`, the contained value
4420 /// is compared with the value.
4421 ///
4422 /// ## Example
4423 /// ```
4424 /// option<int> opt1{};
4425 /// option<int> opt2{42};
4426 ///
4427 /// assert(!(42 <= opt1));
4428 /// assert(42 <= opt2);
4429 /// assert(!(100 <= opt2));
4430 /// ```
4431 template <typename T, typename U>
4432 constexpr bool operator<=(const U& lhs, const option<T>& rhs) {
4433  return rhs.has_value() && lhs <= *rhs;
4434 }
4435 
4436 /// @relates option
4437 /// @brief Compares an @ref option with a value.
4438 ///
4439 /// @details
4440 /// `none` is always less than the value. If not `none`, the contained value
4441 /// is compared with the value.
4442 ///
4443 /// ## Example
4444 /// ```
4445 /// option<int> opt1{};
4446 /// option<int> opt2{42};
4447 ///
4448 /// assert(!(opt1 >= 42));
4449 /// assert(opt2 >= 42);
4450 /// assert(!(opt2 >= 100));
4451 /// ```
4452 template <typename T, typename U>
4453 constexpr bool operator>=(const option<T>& lhs, const U& rhs) {
4454  return lhs.has_value() && *lhs >= rhs;
4455 }
4456 
4457 /// @relates option
4458 /// @brief Compares an @ref option with a value.
4459 ///
4460 /// @details
4461 /// `none` is always less than the value. If not `none`, the contained value
4462 /// is compared with the value.
4463 ///
4464 /// ## Example
4465 /// ```
4466 /// option<int> opt1{};
4467 /// option<int> opt2{42};
4468 ///
4469 /// assert(42 >= opt1);
4470 /// assert(42 >= opt2);
4471 /// assert(!(40 >= opt2));
4472 /// ```
4473 template <typename T, typename U>
4474 constexpr bool operator>=(const U& lhs, const option<T>& rhs) {
4475  return !rhs.has_value() || lhs >= *rhs;
4476 }
4477 
4478 /// @relates option
4479 /// @brief Compares an @ref option with a value.
4480 ///
4481 /// @details
4482 /// `none` is always less than the value. If not `none`, the contained value
4483 /// is compared with the value.
4484 ///
4485 /// ## Example
4486 /// ```
4487 /// option<int> opt1{};
4488 /// option<int> opt2{42};
4489 ///
4490 /// assert((opt1 <=> 42) == std::strong_ordering::less);
4491 /// assert((42 <=> opt1) == std::strong_ordering::greater);
4492 /// assert((opt2 <=> 42) == std::strong_ordering::equal);
4493 /// assert((40 <=> opt2) == std::strong_ordering::less);
4494 /// ```
4495 template <typename T, typename U>
4496 #ifndef DOXYGEN
4497  requires(!detail::is_option_v<U>)
4498 #endif
4499 constexpr
4500 #ifndef DOXYGEN
4501  std::compare_three_way_result_t<std::remove_cvref_t<T>, std::remove_cvref_t<U>>
4502 #else
4503  auto
4504 #endif
4505  operator<=>(const option<T>& lhs, const U& rhs)
4506 #ifndef DOXYGEN
4508 #endif
4509 {
4510  if (lhs.has_value()) {
4511  return *lhs <=> rhs;
4512  } else {
4513  return std::strong_ordering::less;
4514  }
4515 }
4516 
4517 /// @relates option
4518 /// @brief Compares an @ref option with `none`.
4519 ///
4520 /// @details
4521 /// `none` is always less than an @ref option with a contained value.
4522 ///
4523 /// ## Example
4524 /// ```
4525 /// option<int> opt1{};
4526 /// option<int> opt2{42};
4527 ///
4528 /// assert(opt1 == none);
4529 /// assert(!(opt2 == none));
4530 /// ```
4531 template <typename T>
4532 constexpr bool operator==(const option<T>& lhs, [[maybe_unused]] none_t rhs) {
4533  return !lhs.has_value();
4534 }
4535 
4536 /// @relates option
4537 /// @brief Compares an @ref option with `none`.
4538 ///
4539 /// @details
4540 /// `none` is always less than an @ref option with a contained value.
4541 ///
4542 /// ## Example
4543 /// ```
4544 /// option<int> opt1{};
4545 /// option<int> opt2{42};
4546 ///
4547 /// assert(none == opt1);
4548 /// assert(!(none == opt2));
4549 /// ```
4550 template <typename T>
4551 constexpr bool operator==([[maybe_unused]] none_t lhs, const option<T>& rhs) {
4552  return !rhs.has_value();
4553 }
4554 
4555 /// @relates option
4556 /// @brief Compares an @ref option with `none`.
4557 ///
4558 /// @details
4559 /// `none` is always less than an @ref option with a contained value.
4560 ///
4561 /// ## Example
4562 /// ```
4563 /// option<int> opt1{};
4564 /// option<int> opt2{42};
4565 ///
4566 /// assert(!(opt1 != none));
4567 /// assert(opt2 != none);
4568 /// ```
4569 template <typename T>
4570 constexpr bool operator!=(const option<T>& lhs, [[maybe_unused]] none_t rhs) {
4571  return lhs.has_value();
4572 }
4573 
4574 /// @relates option
4575 /// @brief Compares an @ref option with `none`.
4576 ///
4577 /// @details
4578 /// `none` is always less than an @ref option with a contained value.
4579 ///
4580 /// ## Example
4581 /// ```
4582 /// option<int> opt1{};
4583 /// option<int> opt2{42};
4584 ///
4585 /// assert(!(none != opt1));
4586 /// assert(none != opt2);
4587 /// ```
4588 template <typename T>
4589 constexpr bool operator!=([[maybe_unused]] none_t lhs, const option<T>& rhs) {
4590  return rhs.has_value();
4591 }
4592 
4593 /// @relates option
4594 /// @brief Compares an @ref option with `none`.
4595 ///
4596 /// @details
4597 /// `none` is always less than an @ref option with a contained value.
4598 ///
4599 /// ## Example
4600 /// ```
4601 /// option<int> opt1{};
4602 /// option<int> opt2{42};
4603 ///
4604 /// assert(!(opt1 < none));
4605 /// assert(!(opt2 < none));
4606 /// ```
4607 template <typename T>
4608 constexpr bool operator<([[maybe_unused]] const option<T>& lhs,
4609  [[maybe_unused]] none_t rhs) {
4610  return false;
4611 }
4612 
4613 /// @relates option
4614 /// @brief Compares an @ref option with `none`.
4615 ///
4616 /// @details
4617 /// `none` is always less than an @ref option with a contained value.
4618 ///
4619 /// ## Example
4620 /// ```
4621 /// option<int> opt1{};
4622 /// option<int> opt2{42};
4623 ///
4624 /// assert(!(none < opt1));
4625 /// assert(none < opt2);
4626 /// ```
4627 template <typename T>
4628 constexpr bool operator<([[maybe_unused]] none_t lhs, const option<T>& rhs) {
4629  return rhs.has_value();
4630 }
4631 
4632 /// @relates option
4633 /// @brief Compares an @ref option with `none`.
4634 ///
4635 /// @details
4636 /// `none` is always less than an @ref option with a contained value.
4637 ///
4638 /// ## Example
4639 /// ```
4640 /// option<int> opt1{};
4641 /// option<int> opt2{42};
4642 ///
4643 /// assert(!(opt1 > none));
4644 /// assert(opt2 > none);
4645 /// ```
4646 template <typename T>
4647 constexpr bool operator>(const option<T>& lhs, [[maybe_unused]] none_t rhs) {
4648  return lhs.has_value();
4649 }
4650 
4651 /// @relates option
4652 /// @brief Compares an @ref option with `none`.
4653 ///
4654 /// @details
4655 /// `none` is always less than an @ref option with a contained value.
4656 ///
4657 /// ## Example
4658 /// ```
4659 /// option<int> opt1{};
4660 /// option<int> opt2{42};
4661 ///
4662 /// assert(!(none > opt1));
4663 /// assert(!(none > opt2));
4664 /// ```
4665 template <typename T>
4666 constexpr bool operator>([[maybe_unused]] none_t lhs,
4667  [[maybe_unused]] const option<T>& rhs) {
4668  return false;
4669 }
4670 
4671 /// @relates option
4672 /// @brief Compares an @ref option with `none`.
4673 ///
4674 /// @details
4675 /// `none` is always less than an @ref option with a contained value.
4676 ///
4677 /// ## Example
4678 /// ```
4679 /// option<int> opt1{};
4680 /// option<int> opt2{42};
4681 ///
4682 /// assert(opt1 <= none);
4683 /// assert(!(opt2 <= none));
4684 /// ```
4685 template <typename T>
4686 constexpr bool operator<=(const option<T>& lhs, [[maybe_unused]] none_t rhs) {
4687  return !lhs.has_value();
4688 }
4689 
4690 /// @relates option
4691 /// @brief Compares an @ref option with `none`.
4692 ///
4693 /// @details
4694 /// `none` is always less than an @ref option with a contained value.
4695 ///
4696 /// ## Example
4697 /// ```
4698 /// option<int> opt1{};
4699 /// option<int> opt2{42};
4700 ///
4701 /// assert(none <= opt1);
4702 /// assert(none <= opt2);
4703 /// ```
4704 template <typename T>
4705 constexpr bool operator<=([[maybe_unused]] none_t lhs,
4706  [[maybe_unused]] const option<T>& rhs) {
4707  return true;
4708 }
4709 
4710 /// @relates option
4711 /// @brief Compares an @ref option with `none`.
4712 ///
4713 /// @details
4714 /// `none` is always less than an @ref option with a contained value.
4715 ///
4716 /// ## Example
4717 /// ```
4718 /// option<int> opt1{};
4719 /// option<int> opt2{42};
4720 ///
4721 /// assert(opt1 >= none);
4722 /// assert(opt2 >= none);
4723 /// ```
4724 template <typename T>
4725 constexpr bool operator>=([[maybe_unused]] const option<T>& lhs,
4726  [[maybe_unused]] none_t rhs) {
4727  return true;
4728 }
4729 
4730 /// @relates option
4731 /// @brief Compares an @ref option with `none`.
4732 ///
4733 /// @details
4734 /// `none` is always less than an @ref option with a contained value.
4735 ///
4736 /// ## Example
4737 /// ```
4738 /// option<int> opt1{};
4739 /// option<int> opt2{42};
4740 ///
4741 /// assert(none >= opt1);
4742 /// assert(!(none >= opt2));
4743 /// ```
4744 template <typename T>
4745 constexpr bool operator>=([[maybe_unused]] none_t lhs, const option<T>& rhs) {
4746  return !rhs.has_value();
4747 }
4748 
4749 /// @relates option
4750 /// @brief Compares an @ref option with `none`.
4751 ///
4752 /// @details
4753 /// `none` is always less than an @ref option with a contained value.
4754 ///
4755 /// ## Example
4756 /// ```
4757 /// option<int> opt1{};
4758 /// option<int> opt2{42};
4759 ///
4760 /// assert((opt1 <=> none) == std::strong_ordering::equal);
4761 /// assert((none <=> opt1) == std::strong_ordering::equal);
4762 /// assert((opt2 <=> none) == std::strong_ordering::greater);
4763 /// assert((none <=> opt2) == std::strong_ordering::less);
4764 /// ```
4765 template <typename T>
4766 constexpr std::strong_ordering operator<=>(const option<T>& lhs,
4767  [[maybe_unused]] none_t rhs) {
4768  return lhs.has_value() <=> false;
4769 }
4770 
4771 /// @relates option
4772 /// @brief Compares an @ref option with `std::nullopt`.
4773 ///
4774 /// @details
4775 /// `std::nullopt` is always less than an @ref option with a contained value.
4776 ///
4777 /// ## Example
4778 /// ```
4779 /// option<int> opt1{};
4780 /// option<int> opt2{42};
4781 ///
4782 /// assert(opt1 == std::nullopt);
4783 /// assert(!(opt2 == std::nullopt));
4784 /// ```
4785 template <typename T>
4786 constexpr bool operator==(const option<T>& lhs, [[maybe_unused]] std::nullopt_t rhs) {
4787  return !lhs.has_value();
4788 }
4789 
4790 /// @relates option
4791 /// @brief Compares an @ref option with `std::nullopt`.
4792 ///
4793 /// @details
4794 /// `std::nullopt` is always less than an @ref option with a contained value.
4795 ///
4796 /// ## Example
4797 /// ```
4798 /// option<int> opt1{};
4799 /// option<int> opt2{42};
4800 ///
4801 /// assert(std::nullopt == opt1);
4802 /// assert(!(std::nullopt == opt2));
4803 /// ```
4804 template <typename T>
4805 constexpr bool operator==([[maybe_unused]] std::nullopt_t lhs, const option<T>& rhs) {
4806  return !rhs.has_value();
4807 }
4808 
4809 /// @relates option
4810 /// @brief Compares an @ref option with `std::nullopt`.
4811 ///
4812 /// @details
4813 /// `std::nullopt` is always less than an @ref option with a contained value.
4814 ///
4815 /// ## Example
4816 /// ```
4817 /// option<int> opt1{};
4818 /// option<int> opt2{42};
4819 ///
4820 /// assert(!(opt1 != std::nullopt));
4821 /// assert(opt2 != std::nullopt);
4822 /// ```
4823 template <typename T>
4824 constexpr bool operator!=(const option<T>& lhs, [[maybe_unused]] std::nullopt_t rhs) {
4825  return lhs.has_value();
4826 }
4827 
4828 /// @relates option
4829 /// @brief Compares an @ref option with `std::nullopt`.
4830 ///
4831 /// @details
4832 /// `std::nullopt` is always less than an @ref option with a contained value.
4833 ///
4834 /// ## Example
4835 /// ```
4836 /// option<int> opt1{};
4837 /// option<int> opt2{42};
4838 ///
4839 /// assert(!(std::nullopt != opt1));
4840 /// assert(std::nullopt != opt2);
4841 /// ```
4842 template <typename T>
4843 constexpr bool operator!=([[maybe_unused]] std::nullopt_t lhs, const option<T>& rhs) {
4844  return rhs.has_value();
4845 }
4846 
4847 /// @relates option
4848 /// @brief Compares an @ref option with `std::nullopt`.
4849 ///
4850 /// @details
4851 /// `std::nullopt` is always less than an @ref option with a contained value.
4852 ///
4853 /// ## Example
4854 /// ```
4855 /// option<int> opt1{};
4856 /// option<int> opt2{42};
4857 ///
4858 /// assert(!(opt1 < std::nullopt));
4859 /// assert(!(opt2 < std::nullopt));
4860 /// ```
4861 template <typename T>
4862 constexpr bool operator<([[maybe_unused]] const option<T>& lhs,
4863  [[maybe_unused]] std::nullopt_t rhs) {
4864  return false;
4865 }
4866 
4867 /// @relates option
4868 /// @brief Compares an @ref option with `std::nullopt`.
4869 ///
4870 /// @details
4871 /// `std::nullopt` is always less than an @ref option with a contained value.
4872 ///
4873 /// ## Example
4874 /// ```
4875 /// option<int> opt1{};
4876 /// option<int> opt2{42};
4877 ///
4878 /// assert(!(std::nullopt < opt1));
4879 /// assert(std::nullopt < opt2);
4880 /// ```
4881 template <typename T>
4882 constexpr bool operator<([[maybe_unused]] std::nullopt_t lhs, const option<T>& rhs) {
4883  return rhs.has_value();
4884 }
4885 
4886 /// @relates option
4887 /// @brief Compares an @ref option with `std::nullopt`.
4888 ///
4889 /// @details
4890 /// `std::nullopt` is always less than an @ref option with a contained value.
4891 ///
4892 /// ## Example
4893 /// ```
4894 /// option<int> opt1{};
4895 /// option<int> opt2{42};
4896 ///
4897 /// assert(!(opt1 > std::nullopt));
4898 /// assert(opt2 > std::nullopt);
4899 /// ```
4900 template <typename T>
4901 constexpr bool operator>(const option<T>& lhs, [[maybe_unused]] std::nullopt_t rhs) {
4902  return lhs.has_value();
4903 }
4904 
4905 /// @relates option
4906 /// @brief Compares an @ref option with `std::nullopt`.
4907 ///
4908 /// @details
4909 /// `std::nullopt` is always less than an @ref option with a contained value.
4910 ///
4911 /// ## Example
4912 /// ```
4913 /// option<int> opt1{};
4914 /// option<int> opt2{42};
4915 ///
4916 /// assert(!(std::nullopt > opt1));
4917 /// assert(!(std::nullopt > opt2));
4918 /// ```
4919 template <typename T>
4920 constexpr bool operator>([[maybe_unused]] std::nullopt_t lhs,
4921  [[maybe_unused]] const option<T>& rhs) {
4922  return false;
4923 }
4924 
4925 /// @relates option
4926 /// @brief Compares an @ref option with `std::nullopt`.
4927 ///
4928 /// @details
4929 /// `std::nullopt` is always less than an @ref option with a contained value.
4930 ///
4931 /// ## Example
4932 /// ```
4933 /// option<int> opt1{};
4934 /// option<int> opt2{42};
4935 ///
4936 /// assert(opt1 <= std::nullopt);
4937 /// assert(!(opt2 <= std::nullopt));
4938 /// ```
4939 template <typename T>
4940 constexpr bool operator<=(const option<T>& lhs, [[maybe_unused]] std::nullopt_t rhs) {
4941  return !lhs.has_value();
4942 }
4943 
4944 /// @relates option
4945 /// @brief Compares an @ref option with `std::nullopt`.
4946 ///
4947 /// @details
4948 /// `std::nullopt` is always less than an @ref option with a contained value.
4949 ///
4950 /// ## Example
4951 /// ```
4952 /// option<int> opt1{};
4953 /// option<int> opt2{42};
4954 ///
4955 /// assert(std::nullopt <= opt1);
4956 /// assert(std::nullopt <= opt2);
4957 /// ```
4958 template <typename T>
4959 constexpr bool operator<=([[maybe_unused]] std::nullopt_t lhs,
4960  [[maybe_unused]] const option<T>& rhs) {
4961  return true;
4962 }
4963 
4964 /// @relates option
4965 /// @brief Compares an @ref option with `std::nullopt`.
4966 ///
4967 /// @details
4968 /// `std::nullopt` is always less than an @ref option with a contained value.
4969 ///
4970 /// ## Example
4971 /// ```
4972 /// option<int> opt1{};
4973 /// option<int> opt2{42};
4974 ///
4975 /// assert(opt1 >= std::nullopt);
4976 /// assert(opt2 >= std::nullopt);
4977 /// ```
4978 template <typename T>
4979 constexpr bool operator>=([[maybe_unused]] const option<T>& lhs,
4980  [[maybe_unused]] std::nullopt_t rhs) {
4981  return true;
4982 }
4983 
4984 /// @relates option
4985 /// @brief Compares an @ref option with `std::nullopt`.
4986 ///
4987 /// @details
4988 /// `std::nullopt` is always less than an @ref option with a contained value.
4989 ///
4990 /// ## Example
4991 /// ```
4992 /// option<int> opt1{};
4993 /// option<int> opt2{42};
4994 ///
4995 /// assert(std::nullopt >= opt1);
4996 /// assert(!(std::nullopt >= opt2));
4997 /// ```
4998 template <typename T>
4999 constexpr bool operator>=([[maybe_unused]] std::nullopt_t lhs, const option<T>& rhs) {
5000  return !rhs.has_value();
5001 }
5002 
5003 /// @relates option
5004 /// @brief Compares an @ref option with `std::nullopt`.
5005 ///
5006 /// @details
5007 /// `std::nullopt` is always less than an @ref option with a contained value.
5008 ///
5009 /// ## Example
5010 /// ```
5011 /// option<int> opt1{};
5012 /// option<int> opt2{42};
5013 ///
5014 /// assert((opt1 <=> std::nullopt) == std::strong_ordering::equal);
5015 /// assert((std::nullopt <=> opt1) == std::strong_ordering::equal);
5016 /// assert((opt2 <=> std::nullopt) == std::strong_ordering::greater);
5017 /// assert((std::nullopt <=> opt2) == std::strong_ordering::less);
5018 /// ```
5019 template <typename T>
5020 constexpr std::strong_ordering operator<=>(const option<T>& lhs,
5021  [[maybe_unused]] std::nullopt_t rhs) {
5022  return lhs.has_value() <=> false;
5023 }
5024 
5025 /// @relates option
5026 /// @brief Compares an @ref option with `nullptr`.
5027 ///
5028 /// @details
5029 /// `nullptr` is always less than an @ref option with a contained value.
5030 ///
5031 /// This function only participates in overload resolution if the contained
5032 /// type of the @ref option is an lvalue reference.
5033 ///
5034 /// ## Example
5035 /// ```
5036 /// int value = 42;
5037 /// option<int&> opt1{};
5038 /// option<int&> opt2{value};
5039 ///
5040 /// assert(opt1 == nullptr);
5041 /// assert(!(opt2 == nullptr));
5042 /// ```
5043 template <typename T>
5044 #ifndef DOXYGEN
5045  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5046 #endif
5047 constexpr bool operator==(const option<T>& lhs, [[maybe_unused]] std::nullptr_t rhs) {
5048  return !lhs.has_value();
5049 }
5050 
5051 /// @relates option
5052 /// @brief Compares an @ref option with `nullptr`.
5053 ///
5054 /// @details
5055 /// `nullptr` is always less than an @ref option with a contained value.
5056 ///
5057 /// This function only participates in overload resolution if the contained
5058 /// type of the @ref option is an lvalue reference.
5059 ///
5060 /// ## Example
5061 /// ```
5062 /// int value = 42;
5063 /// option<int&> opt1{};
5064 /// option<int&> opt2{value};
5065 ///
5066 /// assert(nullptr == opt1);
5067 /// assert(!(nullptr == opt2));
5068 /// ```
5069 template <typename T>
5070 #ifndef DOXYGEN
5071  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5072 #endif
5073 constexpr bool operator==([[maybe_unused]] std::nullptr_t lhs, const option<T>& rhs) {
5074  return !rhs.has_value();
5075 }
5076 
5077 /// @relates option
5078 /// @brief Compares an @ref option with `nullptr`.
5079 ///
5080 /// @details
5081 /// `nullptr` is always less than an @ref option with a contained value.
5082 ///
5083 /// This function only participates in overload resolution if the contained
5084 /// type of the @ref option is an lvalue reference.
5085 ///
5086 /// ## Example
5087 /// ```
5088 /// int value = 42;
5089 /// option<int&> opt1{};
5090 /// option<int&> opt2{value};
5091 ///
5092 /// assert(!(opt1 != nullptr));
5093 /// assert(opt2 != nullptr);
5094 /// ```
5095 template <typename T>
5096 #ifndef DOXYGEN
5097  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5098 #endif
5099 constexpr bool operator!=(const option<T>& lhs, [[maybe_unused]] std::nullptr_t rhs) {
5100  return lhs.has_value();
5101 }
5102 
5103 /// @relates option
5104 /// @brief Compares an @ref option with `nullptr`.
5105 ///
5106 /// @details
5107 /// `nullptr` is always less than an @ref option with a contained value.
5108 ///
5109 /// This function only participates in overload resolution if the contained
5110 /// type of the @ref option is an lvalue reference.
5111 ///
5112 /// ## Example
5113 /// ```
5114 /// int value = 42;
5115 /// option<int&> opt1{};
5116 /// option<int&> opt2{value};
5117 ///
5118 /// assert(!(nullptr != opt1));
5119 /// assert(nullptr != opt2);
5120 /// ```
5121 template <typename T>
5122 #ifndef DOXYGEN
5123  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5124 #endif
5125 constexpr bool operator!=([[maybe_unused]] std::nullptr_t lhs, const option<T>& rhs) {
5126  return rhs.has_value();
5127 }
5128 
5129 /// @relates option
5130 /// @brief Compares an @ref option with `nullptr`.
5131 ///
5132 /// @details
5133 /// `nullptr` is always less than an @ref option with a contained value.
5134 ///
5135 /// This function only participates in overload resolution if the contained
5136 /// type of the @ref option is an lvalue reference.
5137 ///
5138 /// ## Example
5139 /// ```
5140 /// int value = 42;
5141 /// option<int&> opt1{};
5142 /// option<int&> opt2{value};
5143 ///
5144 /// assert(!(opt1 < nullptr));
5145 /// assert(!(opt2 < nullptr));
5146 /// ```
5147 template <typename T>
5148 #ifndef DOXYGEN
5149  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5150 #endif
5151 constexpr bool operator<([[maybe_unused]] const option<T>& lhs,
5152  [[maybe_unused]] std::nullptr_t rhs) {
5153  return false;
5154 }
5155 
5156 /// @relates option
5157 /// @brief Compares an @ref option with `nullptr`.
5158 ///
5159 /// @details
5160 /// `nullptr` is always less than an @ref option with a contained value.
5161 ///
5162 /// This function only participates in overload resolution if the contained
5163 /// type of the @ref option is an lvalue reference.
5164 ///
5165 /// ## Example
5166 /// ```
5167 /// int value = 42;
5168 /// option<int&> opt1{};
5169 /// option<int&> opt2{value};
5170 ///
5171 /// assert(!(nullptr < opt1));
5172 /// assert(nullptr < opt2);
5173 /// ```
5174 template <typename T>
5175 #ifndef DOXYGEN
5176  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5177 #endif
5178 constexpr bool operator<([[maybe_unused]] std::nullptr_t lhs, const option<T>& rhs) {
5179  return rhs.has_value();
5180 }
5181 
5182 /// @relates option
5183 /// @brief Compares an @ref option with `nullptr`.
5184 ///
5185 /// @details
5186 /// `nullptr` is always less than an @ref option with a contained value.
5187 ///
5188 /// This function only participates in overload resolution if the contained
5189 /// type of the @ref option is an lvalue reference.
5190 ///
5191 /// ## Example
5192 /// ```
5193 /// int value = 42;
5194 /// option<int&> opt1{};
5195 /// option<int&> opt2{value};
5196 ///
5197 /// assert(!(opt1 > nullptr));
5198 /// assert(opt2 > nullptr);
5199 /// ```
5200 template <typename T>
5201 #ifndef DOXYGEN
5202  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5203 #endif
5204 constexpr bool operator>(const option<T>& lhs, [[maybe_unused]] std::nullptr_t rhs) {
5205  return lhs.has_value();
5206 }
5207 
5208 /// @relates option
5209 /// @brief Compares an @ref option with `nullptr`.
5210 ///
5211 /// @details
5212 /// `nullptr` is always less than an @ref option with a contained value.
5213 ///
5214 /// This function only participates in overload resolution if the contained
5215 /// type of the @ref option is an lvalue reference.
5216 ///
5217 /// ## Example
5218 /// ```
5219 /// int value = 42;
5220 /// option<int&> opt1{};
5221 /// option<int&> opt2{value};
5222 ///
5223 /// assert(!(nullptr > opt1));
5224 /// assert(!(nullptr > opt2));
5225 /// ```
5226 template <typename T>
5227 #ifndef DOXYGEN
5228  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5229 #endif
5230 constexpr bool operator>([[maybe_unused]] std::nullptr_t lhs,
5231  [[maybe_unused]] const option<T>& rhs) {
5232  return false;
5233 }
5234 
5235 /// @relates option
5236 /// @brief Compares an @ref option with `nullptr`.
5237 ///
5238 /// @details
5239 /// `nullptr` is always less than an @ref option with a contained value.
5240 ///
5241 /// This function only participates in overload resolution if the contained
5242 /// type of the @ref option is an lvalue reference.
5243 ///
5244 /// ## Example
5245 /// ```
5246 /// int value = 42;
5247 /// option<int&> opt1{};
5248 /// option<int&> opt2{value};
5249 ///
5250 /// assert(opt1 <= nullptr);
5251 /// assert(!(opt2 <= nullptr));
5252 /// ```
5253 template <typename T>
5254 #ifndef DOXYGEN
5255  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5256 #endif
5257 constexpr bool operator<=(const option<T>& lhs, [[maybe_unused]] std::nullptr_t rhs) {
5258  return !lhs.has_value();
5259 }
5260 
5261 /// @relates option
5262 /// @brief Compares an @ref option with `nullptr`.
5263 ///
5264 /// @details
5265 /// `nullptr` is always less than an @ref option with a contained value.
5266 ///
5267 /// This function only participates in overload resolution if the contained
5268 /// type of the @ref option is an lvalue reference.
5269 ///
5270 /// ## Example
5271 /// ```
5272 /// int value = 42;
5273 /// option<int&> opt1{};
5274 /// option<int&> opt2{value};
5275 ///
5276 /// assert(nullptr <= opt1);
5277 /// assert(nullptr <= opt2);
5278 /// ```
5279 template <typename T>
5280 #ifndef DOXYGEN
5281  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5282 #endif
5283 constexpr bool operator<=([[maybe_unused]] std::nullptr_t lhs,
5284  [[maybe_unused]] const option<T>& rhs) {
5285  return true;
5286 }
5287 
5288 /// @relates option
5289 /// @brief Compares an @ref option with `nullptr`.
5290 ///
5291 /// @details
5292 /// `nullptr` is always less than an @ref option with a contained value.
5293 ///
5294 /// This function only participates in overload resolution if the contained
5295 /// type of the @ref option is an lvalue reference.
5296 ///
5297 /// ## Example
5298 /// ```
5299 /// int value = 42;
5300 /// option<int&> opt1{};
5301 /// option<int&> opt2{value};
5302 ///
5303 /// assert(opt1 >= nullptr);
5304 /// assert(opt2 >= nullptr);
5305 /// ```
5306 template <typename T>
5307 #ifndef DOXYGEN
5308  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5309 #endif
5310 constexpr bool operator>=([[maybe_unused]] const option<T>& lhs,
5311  [[maybe_unused]] std::nullptr_t rhs) {
5312  return true;
5313 }
5314 
5315 /// @relates option
5316 /// @brief Compares an @ref option with `nullptr`.
5317 ///
5318 /// @details
5319 /// `nullptr` is always less than an @ref option with a contained value.
5320 ///
5321 /// This function only participates in overload resolution if the contained
5322 /// type of the @ref option is an lvalue reference.
5323 ///
5324 /// ## Example
5325 /// ```
5326 /// int value = 42;
5327 /// option<int&> opt1{};
5328 /// option<int&> opt2{value};
5329 ///
5330 /// assert(nullptr >= opt1);
5331 /// assert(!(nullptr >= opt2));
5332 /// ```
5333 template <typename T>
5334 #ifndef DOXYGEN
5335  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5336 #endif
5337 constexpr bool operator>=([[maybe_unused]] std::nullptr_t lhs, const option<T>& rhs) {
5338  return !rhs.has_value();
5339 }
5340 
5341 /// @relates option
5342 /// @brief Compares an @ref option with `nullptr`.
5343 ///
5344 /// @details
5345 /// `nullptr` is always less than an @ref option with a contained value.
5346 ///
5347 /// This function only participates in overload resolution if the contained
5348 /// type of the @ref option is an lvalue reference.
5349 ///
5350 /// ## Example
5351 /// ```
5352 /// int value = 42;
5353 /// option<int&> opt1{};
5354 /// option<int&> opt2{value};
5355 ///
5356 /// assert((opt1 <=> nullptr) == std::strong_ordering::equal);
5357 /// assert((nullptr <=> opt1) == std::strong_ordering::equal);
5358 /// assert((opt2 <=> nullptr) == std::strong_ordering::greater);
5359 /// assert((nullptr <=> opt2) == std::strong_ordering::less);
5360 /// ```
5361 template <typename T>
5362 #ifndef DOXYGEN
5363  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5364 #endif
5365 constexpr std::strong_ordering operator<=>(const option<T>& lhs,
5366  [[maybe_unused]] std::nullptr_t rhs) {
5367  return lhs.has_value() <=> false;
5368 }
5369 
5370 /// @relates option
5371 /// @brief Compares an @ref option with a pointer.
5372 ///
5373 /// @details
5374 /// An @ref option of an lvalue reference is a smart pointer and is directly
5375 /// comparable with raw pointers, where `none` is null, and a contained
5376 /// value is a non-null address.
5377 ///
5378 /// This function only participates in overload resolution if the contained
5379 /// type of the @ref option is an lvalue reference.
5380 ///
5381 /// ## Example
5382 /// ```
5383 /// int vals[] = {1, 2, 3, 4, 5};
5384 ///
5385 /// option<int&> opt1{};
5386 /// option<int&> opt2{vals[2]};
5387 ///
5388 /// assert(!(opt1 == (vals + 2)));
5389 /// assert(opt2 == (vals + 2));
5390 /// ```
5391 template <typename T, typename U>
5392 #ifndef DOXYGEN
5393  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5394 #endif
5395 constexpr bool operator==(const option<T>& lhs, const U* rhs) {
5396  return &*lhs == rhs;
5397 }
5398 
5399 /// @relates option
5400 /// @brief Compares an @ref option with a pointer.
5401 ///
5402 /// @details
5403 /// An @ref option of an lvalue reference is a smart pointer and is directly
5404 /// comparable with raw pointers, where `none` is null, and a contained
5405 /// value is a non-null address.
5406 ///
5407 /// This function only participates in overload resolution if the contained
5408 /// type of the @ref option is an lvalue reference.
5409 ///
5410 /// ## Example
5411 /// ```
5412 /// int vals[] = {1, 2, 3, 4, 5};
5413 ///
5414 /// option<int&> opt1{};
5415 /// option<int&> opt2{vals[2]};
5416 ///
5417 /// assert(opt1 != (vals + 2));
5418 /// assert(!(opt2 != (vals + 2)));
5419 /// ```
5420 template <typename T, typename U>
5421 #ifndef DOXYGEN
5422  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5423 #endif
5424 constexpr bool operator!=(const option<T>& lhs, const U* rhs) {
5425  return &*lhs != rhs;
5426 }
5427 
5428 /// @relates option
5429 /// @brief Compares an @ref option with a pointer.
5430 ///
5431 /// @details
5432 /// An @ref option of an lvalue reference is a smart pointer and is directly
5433 /// comparable with raw pointers, where `none` is null, and a contained
5434 /// value is a non-null address.
5435 ///
5436 /// This function only participates in overload resolution if the contained
5437 /// type of the @ref option is an lvalue reference.
5438 ///
5439 /// ## Example
5440 /// ```
5441 /// int vals[] = {1, 2, 3, 4, 5};
5442 ///
5443 /// option<int&> opt1{};
5444 /// option<int&> opt2{vals[2]};
5445 ///
5446 /// assert(opt1 < (vals + 2));
5447 /// assert(!(opt2 < (vals + 2)));
5448 /// assert(opt2 < (vals + 3));
5449 /// ```
5450 template <typename T, typename U>
5451 #ifndef DOXYGEN
5452  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5453 #endif
5454 constexpr bool operator<(const option<T>& lhs, const U* rhs) {
5455  return &*lhs < rhs;
5456 }
5457 
5458 /// @relates option
5459 /// @brief Compares an @ref option with a pointer.
5460 ///
5461 /// @details
5462 /// An @ref option of an lvalue reference is a smart pointer and is directly
5463 /// comparable with raw pointers, where `none` is null, and a contained
5464 /// value is a non-null address.
5465 ///
5466 /// This function only participates in overload resolution if the contained
5467 /// type of the @ref option is an lvalue reference.
5468 ///
5469 /// ## Example
5470 /// ```
5471 /// int vals[] = {1, 2, 3, 4, 5};
5472 ///
5473 /// option<int&> opt1{};
5474 /// option<int&> opt2{vals[2]};
5475 ///
5476 /// assert(!(opt1 > (vals + 2)));
5477 /// assert(!(opt2 > (vals + 2)));
5478 /// assert(opt2 > (vals + 1));
5479 /// ```
5480 template <typename T, typename U>
5481 #ifndef DOXYGEN
5482  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5483 #endif
5484 constexpr bool operator>(const option<T>& lhs, const U* rhs) {
5485  return &*lhs > rhs;
5486 }
5487 
5488 /// @relates option
5489 /// @brief Compares an @ref option with a pointer.
5490 ///
5491 /// @details
5492 /// An @ref option of an lvalue reference is a smart pointer and is directly
5493 /// comparable with raw pointers, where `none` is null, and a contained
5494 /// value is a non-null address.
5495 ///
5496 /// This function only participates in overload resolution if the contained
5497 /// type of the @ref option is an lvalue reference.
5498 ///
5499 /// ## Example
5500 /// ```
5501 /// int vals[] = {1, 2, 3, 4, 5};
5502 ///
5503 /// option<int&> opt1{};
5504 /// option<int&> opt2{vals[2]};
5505 ///
5506 /// assert(opt1 <= (vals + 2));
5507 /// assert(!(opt2 <= (vals + 1)));
5508 /// assert(opt2 <= (vals + 2));
5509 /// ```
5510 template <typename T, typename U>
5511 #ifndef DOXYGEN
5512  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5513 #endif
5514 constexpr bool operator<=(const option<T>& lhs, const U* rhs) {
5515  return &*lhs <= rhs;
5516 }
5517 
5518 /// @relates option
5519 /// @brief Compares an @ref option with a pointer.
5520 ///
5521 /// @details
5522 /// An @ref option of an lvalue reference is a smart pointer and is directly
5523 /// comparable with raw pointers, where `none` is null, and a contained
5524 /// value is a non-null address.
5525 ///
5526 /// This function only participates in overload resolution if the contained
5527 /// type of the @ref option is an lvalue reference.
5528 ///
5529 /// ## Example
5530 /// ```
5531 /// int vals[] = {1, 2, 3, 4, 5};
5532 ///
5533 /// option<int&> opt1{};
5534 /// option<int&> opt2{vals[2]};
5535 ///
5536 /// assert(!(opt1 >= (vals + 2)));
5537 /// assert(opt2 >= (vals + 2));
5538 /// assert(!(opt2 >= (vals + 3)));
5539 /// ```
5540 template <typename T, typename U>
5541 #ifndef DOXYGEN
5542  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5543 #endif
5544 constexpr bool operator>=(const option<T>& lhs, const U* rhs) {
5545  return &*lhs >= rhs;
5546 }
5547 
5548 /// @relates option
5549 /// @brief Compares an @ref option with a pointer.
5550 ///
5551 /// @details
5552 /// An @ref option of an lvalue reference is a smart pointer and is directly
5553 /// comparable with raw pointers, where `none` is null, and a contained
5554 /// value is a non-null address.
5555 ///
5556 /// This function only participates in overload resolution if the contained
5557 /// type of the @ref option is an lvalue reference.
5558 ///
5559 /// ## Example
5560 /// ```
5561 /// int vals[] = {1, 2, 3, 4, 5};
5562 ///
5563 /// option<int&> opt1{};
5564 /// option<int&> opt2{vals[2]};
5565 ///
5566 /// assert(!((vals + 2) == opt1));
5567 /// assert((vals + 2) == opt2);
5568 /// ```
5569 template <typename T, typename U>
5570 #ifndef DOXYGEN
5571  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5572 #endif
5573 constexpr bool operator==(const U* lhs, const option<T>& rhs) {
5574  return lhs == &*rhs;
5575 }
5576 
5577 /// @relates option
5578 /// @brief Compares an @ref option with a pointer.
5579 ///
5580 /// @details
5581 /// An @ref option of an lvalue reference is a smart pointer and is directly
5582 /// comparable with raw pointers, where `none` is null, and a contained
5583 /// value is a non-null address.
5584 ///
5585 /// This function only participates in overload resolution if the contained
5586 /// type of the @ref option is an lvalue reference.
5587 ///
5588 /// ## Example
5589 /// ```
5590 /// int vals[] = {1, 2, 3, 4, 5};
5591 ///
5592 /// option<int&> opt1{};
5593 /// option<int&> opt2{vals[2]};
5594 ///
5595 /// assert((vals + 2) != opt1);
5596 /// assert(!((vals + 2) != opt2));
5597 /// ```
5598 template <typename T, typename U>
5599 #ifndef DOXYGEN
5600  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5601 #endif
5602 constexpr bool operator!=(const U* lhs, const option<T>& rhs) {
5603  return lhs != &*rhs;
5604 }
5605 
5606 /// @relates option
5607 /// @brief Compares an @ref option with a pointer.
5608 ///
5609 /// @details
5610 /// An @ref option of an lvalue reference is a smart pointer and is directly
5611 /// comparable with raw pointers, where `none` is null, and a contained
5612 /// value is a non-null address.
5613 ///
5614 /// This function only participates in overload resolution if the contained
5615 /// type of the @ref option is an lvalue reference.
5616 ///
5617 /// ## Example
5618 /// ```
5619 /// int vals[] = {1, 2, 3, 4, 5};
5620 ///
5621 /// option<int&> opt1{};
5622 /// option<int&> opt2{vals[2]};
5623 ///
5624 /// assert(!((vals + 2) < opt1));
5625 /// assert((vals + 2) < opt2);
5626 /// assert(!((vals + 3) < opt2));
5627 /// ```
5628 template <typename T, typename U>
5629 #ifndef DOXYGEN
5630  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5631 #endif
5632 constexpr bool operator<(const U* lhs, const option<T>& rhs) {
5633  return lhs < &*rhs;
5634 }
5635 
5636 /// @relates option
5637 /// @brief Compares an @ref option with a pointer.
5638 ///
5639 /// @details
5640 /// An @ref option of an lvalue reference is a smart pointer and is directly
5641 /// comparable with raw pointers, where `none` is null, and a contained
5642 /// value is a non-null address.
5643 ///
5644 /// This function only participates in overload resolution if the contained
5645 /// type of the @ref option is an lvalue reference.
5646 ///
5647 /// ## Example
5648 /// ```
5649 /// int vals[] = {1, 2, 3, 4, 5};
5650 ///
5651 /// option<int&> opt1{};
5652 /// option<int&> opt2{vals[2]};
5653 ///
5654 /// assert((vals + 2) > opt1);
5655 /// assert((vals + 2) > opt2);
5656 /// assert(!((vals + 1) > opt2));
5657 /// ```
5658 template <typename T, typename U>
5659 #ifndef DOXYGEN
5660  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5661 #endif
5662 constexpr bool operator>(const U* lhs, const option<T>& rhs) {
5663  return lhs > &*rhs;
5664 }
5665 
5666 /// @relates option
5667 /// @brief Compares an @ref option with a pointer.
5668 ///
5669 /// @details
5670 /// An @ref option of an lvalue reference is a smart pointer and is directly
5671 /// comparable with raw pointers, where `none` is null, and a contained
5672 /// value is a non-null address.
5673 ///
5674 /// This function only participates in overload resolution if the contained
5675 /// type of the @ref option is an lvalue reference.
5676 ///
5677 /// ## Example
5678 /// ```
5679 /// int vals[] = {1, 2, 3, 4, 5};
5680 ///
5681 /// option<int&> opt1{};
5682 /// option<int&> opt2{vals[2]};
5683 ///
5684 /// assert(!((vals + 2) <= opt1));
5685 /// assert((vals + 2) <= opt2);
5686 /// assert(!((vals + 3) <= opt2));
5687 /// ```
5688 template <typename T, typename U>
5689 #ifndef DOXYGEN
5690  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5691 #endif
5692 constexpr bool operator<=(const U* lhs, const option<T>& rhs) {
5693  return lhs <= &*rhs;
5694 }
5695 
5696 /// @relates option
5697 /// @brief Compares an @ref option with a pointer.
5698 ///
5699 /// @details
5700 /// An @ref option of an lvalue reference is a smart pointer and is directly
5701 /// comparable with raw pointers, where `none` is null, and a contained
5702 /// value is a non-null address.
5703 ///
5704 /// This function only participates in overload resolution if the contained
5705 /// type of the @ref option is an lvalue reference.
5706 ///
5707 /// ## Example
5708 /// ```
5709 /// int vals[] = {1, 2, 3, 4, 5};
5710 ///
5711 /// option<int&> opt1{};
5712 /// option<int&> opt2{vals[2]};
5713 ///
5714 /// assert((vals + 2) >= opt1);
5715 /// assert(!((vals + 1) >= opt2));
5716 /// assert((vals + 2) >= opt2);
5717 /// ```
5718 template <typename T, typename U>
5719 #ifndef DOXYGEN
5720  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5721 #endif
5722 constexpr bool operator>=(const U* lhs, const option<T>& rhs) {
5723  return lhs >= &*rhs;
5724 }
5725 
5726 /// @relates option
5727 /// @brief Compares an @ref option with a pointer.
5728 ///
5729 /// @details
5730 /// An @ref option of an lvalue reference is a smart pointer and is directly
5731 /// comparable with raw pointers, where `none` is null, and a contained
5732 /// value is a non-null address.
5733 ///
5734 /// This function only participates in overload resolution if the contained
5735 /// type of the @ref option is an lvalue reference.
5736 ///
5737 /// ## Example
5738 /// ```
5739 /// int vals[] = {1, 2, 3, 4, 5};
5740 ///
5741 /// option<int&> opt1{};
5742 /// option<int&> opt2{vals[2]};
5743 ///
5744 /// assert((opt1 <=> (vals + 2)) == std::strong_ordering::less);
5745 /// assert(((vals + 2) <=> opt1) == std::strong_ordering::greater);
5746 /// assert((opt2 <=> (vals + 1)) == std::strong_ordering::greater);
5747 /// assert((opt2 <=> (vals + 2)) == std::strong_ordering::equal);
5748 /// assert((opt2 <=> (vals + 3)) == std::strong_ordering::less);
5749 /// ```
5750 template <typename T, typename U>
5751 #ifndef DOXYGEN
5752  requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5753 #endif
5754 constexpr auto operator<=>(const option<T>& lhs, const U* rhs) {
5755  return &*lhs <=> rhs;
5756 }
5757 
5758 /// @relates option
5759 /// @brief Constructs an @ref option that contains a value.
5760 ///
5761 /// @details
5762 /// This function is the counterpart to @ref none that creates an @ref option
5763 /// that contains a value instead of being `none`. The contained value is
5764 /// constructed in place in the @ref option, which is then RVO returned.
5765 ///
5766 /// A call to this function must explicitly specify the type `T` that the @ref
5767 /// option should contain, and the passed arguments are forwarded to the
5768 /// constructor of that type.
5769 ///
5770 /// ## Example
5771 /// ```
5772 /// int value = 42;
5773 ///
5774 /// auto opt1 = some<void>();
5775 /// auto opt2 = some<int>(value);
5776 /// auto opt3 = some<int&>(value);
5777 ///
5778 /// assert(opt1.has_value());
5779 ///
5780 /// assert(opt2.has_value());
5781 /// assert(*opt2 == 42);
5782 ///
5783 /// assert(opt3.has_value());
5784 /// assert(opt3 == &value);
5785 /// ```
5786 template <typename T, typename... Args>
5787 constexpr option<T> some(Args&&... args) {
5788  return option<T>{std::in_place, std::forward<Args>(args)...};
5789 }
5790 
5791 /// @relates option
5792 /// @brief Constructs an @ref option that contains a value.
5793 ///
5794 /// @details
5795 /// This function is the counterpart to @ref none that creates an @ref option
5796 /// that contains a value instead of being `none`. The contained value is
5797 /// constructed in place in the @ref option, which is then RVO returned.
5798 ///
5799 /// A call to this function must explicitly specify the type `T` that the @ref
5800 /// option should contain, and the passed arguments are forwarded to the
5801 /// constructor of that type.
5802 ///
5803 /// ## Example
5804 /// ```
5805 /// auto opt = some<std::vector<int>>({1, 2, 3, 4, 5});
5806 ///
5807 /// assert(opt.has_value());
5808 /// assert(opt->size() == 5);
5809 /// ```
5810 template <typename T, typename U, typename... Args>
5811 constexpr option<T> some(std::initializer_list<U> ilist, Args&&... args) {
5812  return option<T>{std::in_place, ilist, std::forward<Args>(args)...};
5813 }
5814 
5815 /// @relates option
5816 /// @brief Swaps two @ref option instances
5817 ///
5818 /// @details
5819 /// If both @ref option instances contain a value, the two contained values
5820 /// are swapped directly. Otherwise, if one @ref option contains a value,
5821 /// that value is move constructed into the other @ref option, and the old
5822 /// value is destroyed in place. If both @ref option instances are `none`,
5823 /// nothing is done.
5824 ///
5825 /// This function is `noexcept` if the contained value type is nothrow
5826 /// swappable.
5827 ///
5828 /// # Example
5829 /// ```
5830 /// option<int> opt1{};
5831 /// option<int> opt2{42};
5832 ///
5833 /// swap(opt1, opt2);
5834 ///
5835 /// assert(opt1.has_value());
5836 /// assert(*opt1 == 42);
5837 ///
5838 /// assert(!opt1.has_value());
5839 /// ```
5840 template <typename T>
5841 constexpr void swap(option<T>& a, option<T>& b)
5842 #ifndef DOXYGEN
5843  noexcept(noexcept(a.swap(b)))
5844 #else
5846 #endif
5847 {
5848  a.swap(b);
5849 }
5850 
5851 } // namespace sumty
5852 
5853 #endif