GCC Code Coverage Report


Directory: include/sumty/
File: include/sumty/result.hpp
Date: 2024-04-28 13:27:51
Exec Total Coverage
Lines: 92 101 91.1%
Functions: 172 181 95.0%
Branches: 28 38 73.7%
Decisions: 23 28 82.1%

Line Branch Decision Exec Source
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_RESULT_HPP
17 #define SUMTY_RESULT_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/option.hpp" // IWYU pragma: keep
24 #include "sumty/utils.hpp" // IWYU pragma: export
25 #include "sumty/variant.hpp"
26
27 #include <cstddef>
28 #include <functional>
29 #include <initializer_list>
30 #include <type_traits>
31 #include <utility>
32
33 namespace sumty {
34
35 /// @class result result.hpp <sumty/result.hpp>
36 /// @brief Type that contains an ok value, or an error.
37 ///
38 /// @details
39 /// @ref result is a reimplementation of `std::expected` with several
40 /// improvements. The key difference is that references (lvalue and rvalue) are
41 /// can be used for both the value type and the error type, and `void` can be
42 /// used for the error type (`std::expected` already allows `void` for the
43 /// value type).
44 ///
45 /// Internally, `result<T, E>` is represented as a @ref variant<T, E>. Thus,
46 /// @ref result benefits from the size optimizations implemented by @ref
47 /// variant (see @ref variant documentation for details). A couple special case
48 /// @ref result size examples are shown in the example below.
49 ///
50 /// ```
51 /// struct my_error {}; // NOTE: empty type
52 ///
53 /// assert(sizeof(result<void, my_error>) == sizeof(bool));
54 ///
55 /// assert(sizeof(result<int&, my_error>) == sizeof(int*));
56 /// ```
57 ///
58 /// In practice, the benefit of @ref result over `std::expected` is that @ref
59 /// result can be used in more places, especially with generic code. A generic
60 /// function (function template) that wants to be able to return a value of any
61 /// type, but also allow that return value to instead communicate an error on
62 /// failure can simply return a `result<T, E>`, where `T` is now allowed to be
63 /// a reference or even `void` (and so is `E`, for that matter).
64 ///
65 /// ```
66 /// struct negative_number_error {};
67 ///
68 /// // If value is negative, returns a negative_number_error. Otherwise,
69 /// // invokes func with the value as an argument and returns the result,
70 /// // even if the result is void or a reference.
71 /// template <typename F>
72 /// result<std::invoke_result_t<F>, negative_number_error>
73 /// call_if_non_negative(int value, F&& func) {
74 /// if (value < 0) {
75 /// return error<negative_number_error>();
76 /// }
77 /// // sumty::invoke needed to handle `void` return type
78 /// return invoke(std::forward<F>(func), value);
79 /// }
80 /// ```
81 ///
82 /// The power of @ref result is also enhanced when used in combination with
83 /// @ref error_set. @ref error_set makes it easy to represent a set of
84 /// different error possibilities of different types in a single value, and
85 /// simplifies error propagation when used with @ref result. See the
86 /// documentation of @ref error_set for more details and examples.
87 template <typename T, typename E>
88 class result : variant<T, E> {
89 private:
90 182 [[nodiscard]] constexpr variant<T, E>& res_() & noexcept {
91 182 return *static_cast<variant<T, E>*>(this);
92 }
93
94 202 [[nodiscard]] constexpr const variant<T, E>& res_() const& noexcept {
95 202 return *static_cast<const variant<T, E>*>(this);
96 }
97
98 54 [[nodiscard]] constexpr variant<T, E>&& res_() && {
99 54 return std::move(*static_cast<variant<T, E>*>(this));
100 }
101
102 [[nodiscard]] constexpr const variant<T, E>& res_() const&& {
103 return std::move(*static_cast<const variant<T, E>*>(this));
104 }
105
106 template <typename, typename>
107 friend class result;
108
109 public:
110 #ifndef DOXYGEN
111 using value_type = typename detail::traits<T>::value_type;
112 using reference = typename detail::traits<T>::reference;
113 using const_reference = typename detail::traits<T>::const_reference;
114 using rvalue_reference = typename detail::traits<T>::rvalue_reference;
115 using const_rvalue_reference = typename detail::traits<T>::const_rvalue_reference;
116 using pointer = typename detail::traits<T>::pointer;
117 using const_pointer = typename detail::traits<T>::const_pointer;
118
119 using error_type = typename detail::traits<E>::value_type;
120 using error_reference = typename detail::traits<E>::reference;
121 using error_const_reference = typename detail::traits<E>::const_reference;
122 using error_rvalue_reference = typename detail::traits<E>::rvalue_reference;
123 using error_const_rvalue_reference = typename detail::traits<E>::const_rvalue_reference;
124 using error_pointer = typename detail::traits<E>::pointer;
125 using error_const_pointer = typename detail::traits<E>::const_pointer;
126 #else
127 using value_type = ...;
128 using reference = ...;
129 using const_reference = ...;
130 using rvalue_reference = ...;
131 using const_rvalue_reference = ...;
132 using pointer = ...;
133 using const_pointer = ...;
134
135 using error_type = ...;
136 using error_reference = ...;
137 using error_const_reference = ...;
138 using error_rvalue_reference = ...;
139 using error_const_rvalue_reference = ...;
140 using error_pointer = ...;
141 using error_const_pointer = ...;
142 #endif
143
144 template <typename U>
145 using rebind = result<U, E>;
146
147 template <typename V>
148 using rebind_error = result<T, V>;
149
150 // For compatibility with std::expected
151 using unexpected_type = result<never, E>;
152
153 /// @brief Default constructor
154 ///
155 /// @details
156 /// Initializes the @ref result with a default constructed ok value.
157 ///
158 /// ## Example
159 /// ```
160 /// result<int, std::string> res{};
161 ///
162 /// assert(res.has_value());
163 ///
164 /// assert(*res == 0);
165 /// ```
166 18 constexpr result()
167 #ifndef DOXYGEN
168 noexcept(std::is_nothrow_default_constructible_v<variant<T, E>>)
169 requires(std::is_default_constructible_v<variant<T, E>>)
170 = default;
171 #else
172 CONDITIONALLY_NOEXCEPT;
173 #endif
174
175 /// @brief Copy constructor
176 ///
177 /// @details
178 /// If the source @ref result has an ok value, the new @ref result is
179 /// initialized with a copy constructed ok value. If the source @ref result
180 /// has an error value, the new @ref result is initialized with a copy
181 /// constructed error.
182 ///
183 /// ## Example
184 /// ```
185 /// result<int, std::string> res1{42};
186 /// result<int, std::string> res2{in_place_error, "oh no"};
187 ///
188 /// result<int, std::string> res1_copy{res1};
189 /// result<int, std::string> res2_copy{res2};
190 ///
191 /// assert(res1_copy.has_value());
192 /// assert(*res1_copy == 42);
193 ///
194 /// assert(!res2_copy.has_value());
195 /// assert(res2_copy.error() == "oh no");
196 /// ```
197 4 constexpr result(const result&)
198 #ifndef DOXYGEN
199 noexcept(std::is_nothrow_copy_constructible_v<variant<T, E>>)
200 requires(std::is_copy_constructible_v<variant<T, E>>)
201 = default;
202 #else
203 CONDITIONALLY_NOEXCEPT;
204 #endif
205
206 /// @brief Move constructor
207 ///
208 /// @details
209 /// If the source @ref result has an ok value, the new @ref result is
210 /// initialized with a move constructed ok value. If the source @ref result
211 /// has an error value, the new @ref result is initialized with a move
212 /// constructed error.
213 ///
214 /// ## Example
215 /// ```
216 /// result<int, std::string> res1{42};
217 /// result<int, std::string> res2{in_place_error, "oh no"};
218 ///
219 /// result<int, std::string> res1_copy{std::move(res1)};
220 /// result<int, std::string> res2_copy{std::move(res2)};
221 ///
222 /// assert(res1_copy.has_value());
223 /// assert(*res1_copy == 42);
224 ///
225 /// assert(!res2_copy.has_value());
226 /// assert(res2_copy.error() == "oh no");
227 /// ```
228 constexpr result(result&&)
229 #ifndef DOXYGEN
230 noexcept(std::is_nothrow_move_constructible_v<variant<T, E>>)
231 requires(std::is_move_constructible_v<variant<T, E>>)
232 = default;
233 #else
234 CONDITIONALLY_NOEXCEPT;
235 #endif
236
237 /// @brief Emplacement constructor
238 ///
239 /// @details
240 /// The @ref result is initialized such that an ok value is constructed in
241 /// place from the forwarded arguments.
242 ///
243 /// This constructor is `explicit` if `inplace` is the only argument.
244 ///
245 /// ## Example
246 /// ```
247 /// result<std::string, std::string> res{std::in_place, 5, 'a'};
248 ///
249 /// assert(res.has_value());
250 ///
251 /// assert(*res == "aaaaa");
252 /// ```
253 template <typename... Args>
254 #ifndef DOXYGEN
255 explicit(sizeof...(Args) == 0)
256 #else
257 CONDITONALLY_EXPLICIT
258 #endif
259 // NOLINTNEXTLINE(hicpp-explicit-conversions)
260 28 constexpr result([[maybe_unused]] std::in_place_t inplace, Args&&... args)
261 28 : variant<T, E>(std::in_place_index<0>, std::forward<Args>(args)...) {
262 28 }
263
264 /// @brief Emplacement constructor with initializer list
265 ///
266 /// @details
267 /// The @ref result is initialized such that an ok value is constructed in
268 /// place from the forwarded arguments.
269 ///
270 /// ## Example
271 /// ```
272 /// result<std::vector<int>, std::string> res{
273 /// std::in_place, {1, 2, 3, 4, 5}};
274 ///
275 /// assert(res.has_value());
276 ///
277 /// assert(res->size() == 5);
278 /// ```
279 template <typename U, typename... Args>
280 constexpr result([[maybe_unused]] std::in_place_t inplace,
281 std::initializer_list<U> init,
282 Args&&... args)
283 : variant<T, E>(std::in_place_index<0>, init, std::forward<Args>(args)...) {}
284
285 /// @brief Emplacement constructor
286 ///
287 /// @details
288 /// The @ref result is initialized such that an ok value is constructed in
289 /// place from the forwarded arguments.
290 ///
291 /// This constructor is `explicit` if `inplace` is the only argument.
292 ///
293 /// ## Example
294 /// ```
295 /// result<std::string, std::string> res{std::in_place_index<0>, 5, 'a'};
296 ///
297 /// assert(res.has_value());
298 ///
299 /// assert(*res == "aaaaa");
300 /// ```
301 template <typename... Args>
302 #ifndef DOXYGEN
303 explicit(sizeof...(Args) == 0)
304 #else
305 CONDITIONALLY_EXPLICIT
306 #endif
307 // NOLINTNEXTLINE(hicpp-explicit-conversions)
308 constexpr result(std::in_place_index_t<0> inplace, Args&&... args)
309 : variant<T, E>(inplace, std::forward<Args>(args)...) {
310 }
311
312 /// @brief Emplacement constructor with initializer list
313 ///
314 /// @details
315 /// The @ref result is initialized such that an ok value is constructed in
316 /// place from the forwarded arguments.
317 ///
318 /// ## Example
319 /// ```
320 /// result<std::vector<int>, std::string> res{
321 /// std::in_place_index<0>, {1, 2, 3, 4, 5}};
322 ///
323 /// assert(res.has_value());
324 ///
325 /// assert(res->size() == 5);
326 /// ```
327 template <typename U, typename... Args>
328 constexpr result(std::in_place_index_t<0> inplace,
329 std::initializer_list<U> init,
330 Args&&... args)
331 : variant<T, E>(inplace, init, std::forward<Args>(args)...) {}
332
333 /// @brief Error emplacement constructor
334 ///
335 /// @details
336 /// The @ref result is initialized such that an error value is constructed
337 /// in place from the forwarded arguments.
338 ///
339 /// ## Example
340 /// ```
341 /// result<void, std::string> res{in_place_error, 5, 'a'};
342 ///
343 /// assert(!res.has_value());
344 ///
345 /// assert(res.error() == "aaaaa");
346 /// ```
347 template <typename... Args>
348 #ifndef DOXYGEN
349 explicit(sizeof...(Args) == 0)
350 #else
351 CONDITONALLY_EXPLICIT
352 #endif
353 // NOLINTNEXTLINE(hicpp-explicit-conversions)
354 65 constexpr result(in_place_error_t inplace, Args&&... args)
355 65 : variant<T, E>(inplace, std::forward<Args>(args)...) {
356 65 }
357
358 /// @brief Error emplacement constructor with initializer list
359 ///
360 /// @details
361 /// The @ref result is initialized such that an error value is constructed
362 /// in place from the forwarded arguments.
363 ///
364 /// ## Example
365 /// ```
366 /// result<void, std::vector<int>> res{in_place_error, {1, 2, 3, 4, 5}};
367 ///
368 /// assert(!res.has_value());
369 ///
370 /// assert(res.error().size() == 5);
371 /// ```
372 template <typename U, typename... Args>
373 constexpr result(in_place_error_t inplace,
374 std::initializer_list<U> init,
375 Args&&... args)
376 : variant<T, E>(inplace, init, std::forward<Args>(args)...) {}
377
378 /// @brief Forwarding constructor
379 ///
380 /// @details
381 /// The @ref result is initialized such that it contains an ok value that
382 /// is constructed in place from the forwarded value.
383 ///
384 /// This constructor only participates in overload resolution if the ok
385 /// value is constructible from the forwarded value, the forwarded value is
386 /// not of type `std::in_place_t`, `sumty::in_place_t`,
387 /// `std::in_place_index_t<0>`, `sumty::in_place_index_t<0>`,
388 /// `std::in_place_index_t<1>`, `sumty::in_place_index_t<1>`, or
389 /// `sumty::in_place_error_t`, and either the ok value type is a scalar or
390 /// the forwarded value is not a @ref result instance.
391 ///
392 /// This constructor is `explicit` if the forwarded value is not implicitly
393 /// convertible to `T`.
394 ///
395 /// ## Example
396 /// ```
397 /// float value = 3.14;
398 ///
399 /// result<int, std::string> res{value};
400 ///
401 /// assert(res.has_value());
402 ///
403 /// assert(*res == 3);
404 /// ```
405 template <typename U>
406 #ifndef DOXYGEN
407 requires(std::is_constructible_v<variant<T, E>, std::in_place_index_t<0>, U &&> &&
408 !std::is_same_v<std::remove_cvref_t<U>, std::in_place_t> &&
409 !std::is_same_v<std::remove_cvref_t<U>, std::in_place_index_t<0>> &&
410 !std::is_same_v<std::remove_cvref_t<U>, std::in_place_index_t<1>> &&
411 (!std::is_scalar_v<std::remove_cvref_t<T>> ||
412 !detail::is_result_v<std::remove_cvref_t<U>>))
413 explicit(!detail::traits<T>::template is_convertible_from<U>)
414 #else
415 CONDITIONALLY_EXPLICIT
416 #endif
417 // NOLINTNEXTLINE(hicpp-explicit-conversions)
418 34 constexpr result(U&& value)
419 34 : variant<T, E>(std::in_place_index<0>, std::forward<U>(value)) {
420 34 }
421
422 /// @brief Converting copy constructor
423 ///
424 /// @details
425 /// This constructor converts a @ref result with one pair of ok and error
426 /// types into a @result of a different pair of ok and error types. This
427 /// constructor behaves much like the copy constructor, except that a type
428 /// conversion may occur.
429 ///
430 /// This constructor only particpates in overload resolution if the ok type
431 /// `T` of the destination @ref result is constructible from the ok type
432 /// `U` of the source @ref result, *and* the error type `E` of the
433 /// destiantion @ref result is constructible from the error type `V` of the
434 /// source @ref result.
435 ///
436 /// This constructor is `explicit` if either `U` or `V` is not implicitly
437 /// convertible to `T` or `E`, respectively.
438 ///
439 /// ## Example
440 /// ```
441 /// result<float, const char*> res1{3.14};
442 /// result<float, const char*> res2{in_place_error, "oh no"};
443 ///
444 /// result<int, std::string> res3{res1};
445 /// result<int, std::string> res4{res2};
446 ///
447 /// assert(res3.has_value());
448 /// assert(*res3 == 3);
449 ///
450 /// assert(!res4.has_value());
451 /// assert(res4.error() == "oh no");
452 /// ```
453 template <typename U, typename V>
454 #ifndef DOXYGEN
455 requires(((std::is_void_v<U> && detail::traits<T>::is_default_constructible) ||
456 std::is_constructible_v<variant<T, E>,
457 std::in_place_index_t<0>,
458 typename detail::traits<U>::const_reference>) &&
459 ((std::is_void_v<V> && detail::traits<E>::is_default_constructible) ||
460 std::is_constructible_v<variant<T, E>,
461 std::in_place_index_t<1>,
462 typename detail::traits<E>::const_reference>))
463 explicit((!std::is_void_v<U> && !detail::traits<T>::template is_convertible_from<U>) ||
464 (!std::is_void_v<V> && !detail::traits<E>::template is_convertible_from<V>))
465 #else
466 CONDITIONALLY_EXPLICIT
467 #endif
468 // NOLINTNEXTLINE(hicpp-explicit-conversions)
469 constexpr result(const result<U, V>& other)
470 : variant<T, E>(detail::uninit) {
471 other.res_().visit_informed([this](auto&& value, auto info) {
472 res_().template uninit_emplace<info.index>(
473 std::forward<decltype(value)>(value));
474 });
475 }
476
477 /// @brief Converting move constructor
478 ///
479 /// @details
480 /// This constructor converts a @ref result with one pair of ok and error
481 /// types into a @result of a different pair of ok and error types. This
482 /// constructor behaves much like the move constructor, except that a type
483 /// conversion may occur.
484 ///
485 /// This constructor only particpates in overload resolution if the ok type
486 /// `T` of the destination @ref result is constructible from the moved ok
487 /// type `U` of the source @ref result, *and* the error type `E` of the
488 /// destiantion @ref result is constructible from the move error type `V`
489 /// of the source @ref result.
490 ///
491 /// This constructor is `explicit` if either `U` or `V` is not implicitly
492 /// convertible to `T` or `E`, respectively.
493 ///
494 /// ## Example
495 /// ```
496 /// result<float, const char*> res1{3.14};
497 /// result<float, const char*> res2{in_place_error, "oh no"};
498 ///
499 /// result<int, std::string> res3{std::move(res1)};
500 /// result<int, std::string> res4{std::move(res2)};
501 ///
502 /// assert(res3.has_value());
503 /// assert(*res3 == 3);
504 ///
505 /// assert(!res4.has_value());
506 /// assert(res4.error() == "oh no");
507 /// ```
508 template <typename U, typename V>
509 #ifndef DOXYGEN
510 requires(((std::is_void_v<U> && detail::traits<T>::is_default_constructible) ||
511 std::is_constructible_v<variant<T, E>,
512 std::in_place_index_t<0>,
513 typename detail::traits<U>::rvalue_reference>) &&
514 ((std::is_void_v<V> && detail::traits<E>::is_default_constructible) ||
515 std::is_constructible_v<variant<T, E>,
516 std::in_place_index_t<1>,
517 typename detail::traits<E>::rvalue_reference>))
518 explicit((!std::is_void_v<U> && !detail::traits<T>::template is_convertible_from<U>) ||
519 (!std::is_void_v<V> && !detail::traits<E>::template is_convertible_from<V>))
520 #else
521 CONDITIONALLY_EXPLICIT
522 #endif
523 // clang-format off
524 // NOLINTNEXTLINE(hicpp-explicit-conversions,cppcoreguidelines-rvalue-reference-param-not-moved)
525 54 constexpr result(result<U, V>&& other)
526 // clang-format on
527 54 : variant<T, E>(detail::uninit) {
528
1/2
✓ Branch 3 taken 27 times.
✗ Branch 4 not taken.
108 std::move(other).res_().visit_informed([this](auto&& value, auto info) {
529 27 res_().template uninit_emplace<info.index>(
530 std::forward<decltype(value)>(value));
531 });
532 54 }
533
534 /// @brief Destructor
535 ///
536 /// @details
537 /// Destroys the contained value in place.
538 ///
539 /// The desctructor is `noexcept` if both `T` and `E` are nothrow
540 /// destructible.
541 173 constexpr ~result()
542 #ifndef DOXYGEN
543 noexcept(std::is_nothrow_destructible_v<variant<T, E>>) = default;
544 #else
545 CONDITIONALLY_NOEXCEPT;
546 #endif
547
548 /// @brief Copy assignment operator
549 ///
550 /// @details
551 /// The destination @ref result is reassigned such that it will now contain
552 /// a copy of the contained value of the source @ref result, which may be
553 /// either the ok type or the error type.
554 ///
555 /// If both the source and destination contain the ok type, or both contain
556 /// the error type, the values are copy assigned directly. Otherwise, the
557 /// old value in the destination is destroyed and the new value is copy
558 /// constructed.
559 ///
560 /// This function is `noexcept` if both `T` and `E` are all of the
561 /// following:
562 /// * Nothrow copy assignable
563 /// * Nothrow copy constructible
564 /// * Nothrow destructible
565 ///
566 /// ## Example
567 /// ```
568 /// result<float, const char*> res1{3.14};
569 /// result<float, const char*> res2{in_place_error, "oh no"};
570 ///
571 /// result<int, std::string> res3{};
572 /// result<int, std::string> res4{};
573 ///
574 /// res3 = res1;
575 /// res4 = res2;
576 ///
577 /// assert(res3.has_value());
578 /// assert(*res3 == 3);
579 ///
580 /// assert(!res4.has_value());
581 /// assert(res4.error() == "oh no");
582 /// ```
583 constexpr result& operator=(const result&)
584 #ifndef DOXYGEN
585 noexcept(std::is_nothrow_copy_assignable_v<variant<T, E>>)
586 requires(std::is_copy_assignable_v<variant<T, E>>)
587 = default;
588 #else
589 CONDITIONALLY_NOEXCEPT;
590 #endif
591
592 /// @brief Move assignment operator
593 ///
594 /// @details
595 /// The destination @ref result is reassigned such that it will now contain
596 /// the moved contained value of the source @ref result, which may be
597 /// either the ok type or the error type.
598 ///
599 /// If both the source and destination contain the ok type, or both contain
600 /// the error type, the values are move assigned directly. Otherwise, the
601 /// old value in the destination is destroyed and the new value is move
602 /// constructed.
603 ///
604 /// This function is `noexcept` if both `T` and `E` are all of the
605 /// following:
606 /// * Nothrow move assignable
607 /// * Nothrow move constructible
608 /// * Nothrow destructible
609 ///
610 /// ## Example
611 /// ```
612 /// result<float, const char*> res1{3.14};
613 /// result<float, const char*> res2{in_place_error, "oh no"};
614 ///
615 /// result<int, std::string> res3{};
616 /// result<int, std::string> res4{};
617 ///
618 /// res3 = std::move(res1);
619 /// res4 = std::move(res2);
620 ///
621 /// assert(res3.has_value());
622 /// assert(*res3 == 3);
623 ///
624 /// assert(!res4.has_value());
625 /// assert(res4.error() == "oh no");
626 /// ```
627 8 constexpr result& operator=(result&&)
628 #ifndef DOXYGEN
629 noexcept(std::is_nothrow_move_assignable_v<variant<T, E>>)
630 requires(std::is_move_assignable_v<variant<T, E>>)
631 = default;
632 #else
633 CONDITIONALLY_NOEXCEPT;
634 #endif
635
636 /// @brief Value assignment operator
637 ///
638 /// @details
639 /// Sets the @ref result to contain the forwarded ok value, converted to
640 /// `T`. If the @ref result already contains an ok value, the forwarded
641 /// value is assigned directly to the contained value. Otherwise, the
642 /// error type is destroyed, and the ok type is constructed from the
643 /// forwarded value.
644 ///
645 /// This function only participates in overload resolution if:
646 /// * The source value is not a @ref result
647 /// * `T` is constructible from `U`
648 /// * `T` is assignable from `U`
649 ///
650 /// ## Example
651 /// ```
652 /// result<int, std::string> res{};
653 ///
654 /// res = 3.14;
655 ///
656 /// assert(res.has_value());
657 /// assert(*res == 3);
658 /// ```
659 template <typename U>
660 #ifndef DOXYGEN
661 requires(!std::is_same_v<result, std::remove_cvref_t<U>> &&
662 !detail::is_result_v<std::remove_cvref_t<U>> &&
663 detail::traits<T>::template is_constructible<U> &&
664 detail::traits<T>::template is_assignable<U>)
665 #endif
666 1 constexpr result<T, E>& operator=(U&& value) {
667
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1 if (res_().index() == 0) {
668 1 res_()[index<0>] = std::forward<U>(value);
669 } else {
670 res_().template emplace<0>(std::forward<U>(value));
671 }
672 1 return *this;
673 }
674
675 /// @brief Implicit conversion to `bool`.
676 ///
677 /// @details
678 /// This implicit conversion allows a @ref result to be used directly in a
679 /// condition to check if the @ref result contains an ok value.
680 ///
681 /// ## Example
682 /// ```
683 /// result<int, std::string> res1{42};
684 /// result<int, std::string> res2 = error<std::string>("oh no");
685 ///
686 /// if (res1) {
687 /// assert(*res1 == 42);
688 /// } else {
689 /// assert(false);
690 /// }
691 ///
692 /// if (res2) {
693 /// assert(false);
694 /// } else {
695 /// assert(res2.error() == "oh no");
696 /// }
697 /// ```
698 // NOLINTNEXTLINE(hicpp-explicit-conversions)
699 constexpr operator bool() const noexcept { return res_().index() == 0; }
700
701 /// @brief Returns `true` if the @ref result contains an ok value
702 ///
703 /// @details
704 /// ## Example
705 /// ```
706 /// result<int, std::string> res1{42};
707 /// result<int, std::string> res2{error<std::string>("oh no")};
708 ///
709 /// assert(res1.has_value());
710 /// assert(!res1.has_value());
711 /// ```
712 85 [[nodiscard]] constexpr bool has_value() const noexcept { return res_().index() == 0; }
713
714 /// @brief Returns `true` if the @ref result contains an ok value
715 ///
716 /// @details
717 /// ## Example
718 /// ```
719 /// result<int, std::string> res1{42};
720 /// result<int, std::string> res2{error<std::string>("oh no")};
721 ///
722 /// assert(res1.is_ok());
723 /// assert(!res1.is_ok());
724 /// ```
725 [[nodiscard]] constexpr bool is_ok() const noexcept { return res_().index() == 0; }
726
727 /// @brief Returns `true` if the @ref result contains an error value
728 ///
729 /// @details
730 /// ## Example
731 /// ```
732 /// result<int, std::string> res1{42};
733 /// result<int, std::string> res2{error<std::string>("oh no")};
734 ///
735 /// assert(!res1.is_error());
736 /// assert(res1.is_error());
737 /// ```
738 [[nodiscard]] constexpr bool is_error() const noexcept { return res_().index() != 0; }
739
740 /// @brief Accesses the ok value contained in the @ref result
741 ///
742 /// @details
743 /// This operator does not check if the @ref result contains an ok value.
744 /// Use of this operator when the @ref result contains and error results in
745 /// undefined behavior.
746 ///
747 /// ## Example
748 /// ```
749 /// result<int, std::string> res{42};
750 ///
751 /// assert(*res == 42);
752 /// ```
753 44 [[nodiscard]] constexpr reference operator*() & noexcept { return res_()[index<0>]; }
754
755 /// @brief Accesses the ok value contained in the @ref result
756 ///
757 /// @details
758 /// This operator does not check if the @ref result contains an ok value.
759 /// Use of this operator when the @ref result contains an error results in
760 /// undefined behavior.
761 ///
762 /// ## Example
763 /// ```
764 /// const result<int, std::string> res{42};
765 ///
766 /// assert(*res == 42);
767 /// ```
768 15 [[nodiscard]] constexpr const_reference operator*() const& noexcept {
769 15 return res_()[index<0>];
770 }
771
772 /// @brief Accesses the ok value contained in the @ref result
773 ///
774 /// @details
775 /// This operator does not check if the @ref result contains an ok value.
776 /// Use of this operator when the @ref result contains an error results in
777 /// undefined behavior.
778 ///
779 /// ## Example
780 /// ```
781 /// result<int, std::string> res{42};
782 ///
783 /// assert(*std::move(res) == 42);
784 /// ```
785 [[nodiscard]] constexpr rvalue_reference operator*() && {
786 return std::move(*this).res_()[index<0>];
787 }
788
789 /// @brief Accesses the ok value contained in the @ref result
790 ///
791 /// @details
792 /// This operator does not check if the @ref result contains an ok value.
793 /// Use of this operator when the @ref result contains an error results in
794 /// undefined behavior.
795 ///
796 /// ## Example
797 /// ```
798 /// const result<int, std::string> res{42};
799 ///
800 /// assert(*std::move(res) == 42);
801 /// ```
802 [[nodiscard]] constexpr const_rvalue_reference operator*() const&& {
803 return std::move(*this).res_()[index<0>];
804 }
805
806 /// @brief Accesses members of the ok value contained in the @ref result
807 ///
808 /// @details
809 /// This operator does not check if the @ref result contains an ok value.
810 /// Use of this operator when the @ref result contains an error results in
811 /// undefined behavior.
812 ///
813 /// ## Example
814 /// ```
815 /// result<std::string, int> res{"hello"};
816 ///
817 /// assert(res->size() == 5);
818 /// ```
819 [[nodiscard]] constexpr pointer operator->() noexcept { return &res_()[index<0>]; }
820
821 /// @brief Accesses members of the ok value contained in the @ref result
822 ///
823 /// @details
824 /// This operator does not check if the @ref result contains an ok value.
825 /// Use of this operator when the @ref result contains an error results in
826 /// undefined behavior.
827 ///
828 /// ## Example
829 /// ```
830 /// const result<std::string, int> res{"hello"};
831 ///
832 /// assert(res->size() == 5);
833 /// ```
834 [[nodiscard]] constexpr const_pointer operator->() const noexcept {
835 return &res_()[index<0>];
836 }
837
838 /// @brief Accesses the ok value contained in the @ref result
839 ///
840 /// @details
841 /// This function first checks if the @ref result contains an ok value
842 /// before attempting to access the value. If the @ref result contains an
843 /// error, then this function throws an exception.
844 ///
845 /// ## Example
846 /// ```
847 /// result<int, std::string> res{42};
848 ///
849 /// assert(res.value() == 42);
850 /// ```
851 ///
852 /// @throws bad_result_access Thrown if the @ref result contains an error
853 28 [[nodiscard]] constexpr reference value() & {
854
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 14 times.
28 if (res_().index() != 0) {
855 if constexpr (std::is_void_v<E>) {
856 throw bad_result_access<void>();
857 } else {
858 throw bad_result_access<std::remove_cvref_t<E>>(res_()[index<1>]);
859 }
860 }
861 28 return res_()[index<0>];
862 }
863
864 /// @brief Accesses the ok value contained in the @ref result
865 ///
866 /// @details
867 /// This function first checks if the @ref result contains an ok value
868 /// before attempting to access the value. If the @ref result contains an
869 /// error, then this function throws an exception.
870 ///
871 /// ## Example
872 /// ```
873 /// const result<int, std::string> res{42};
874 ///
875 /// assert(res.value() == 42);
876 /// ```
877 ///
878 /// @throws bad_result_access Thrown if the @ref result contains an error
879 [[nodiscard]] constexpr const_reference value() const& {
880 if (res_().index() != 0) {
881 if constexpr (std::is_void_v<E>) {
882 throw bad_result_access<void>();
883 } else {
884 throw bad_result_access<std::remove_cvref_t<E>>(res_()[index<1>]);
885 }
886 }
887 return res_()[index<0>];
888 }
889
890 /// @brief Accesses the ok value contained in the @ref result
891 ///
892 /// @details
893 /// This function first checks if the @ref result contains an ok value
894 /// before attempting to access the value. If the @ref result contains an
895 /// error, then this function throws an exception.
896 ///
897 /// ## Example
898 /// ```
899 /// result<int, std::string> res{42};
900 ///
901 /// assert(std::move(res).value() == 42);
902 /// ```
903 ///
904 /// @throws bad_result_access Thrown if the @ref result contains an error
905 [[nodiscard]] constexpr rvalue_reference value() && {
906 if (res_().index() != 0) {
907 if constexpr (std::is_void_v<E>) {
908 throw bad_result_access<void>();
909 } else {
910 throw bad_result_access<std::remove_cvref_t<E>>(
911 std::move(*this).res_()[index<1>]);
912 }
913 }
914 return std::move(*this).res_()[index<0>];
915 }
916
917 /// @brief Accesses the ok value contained in the @ref result
918 ///
919 /// @details
920 /// This function first checks if the @ref result contains an ok value
921 /// before attempting to access the value. If the @ref result contains an
922 /// error, then this function throws an exception.
923 ///
924 /// ## Example
925 /// ```
926 /// const result<int, std::string> res{42};
927 ///
928 /// assert(std::move(res).value() == 42);
929 /// ```
930 ///
931 /// @throws bad_result_access Thrown if the @ref result contains an error
932 [[nodiscard]] constexpr rvalue_reference value() const&& {
933 if (res_().index() != 0) {
934 if constexpr (std::is_void_v<E>) {
935 throw bad_result_access<void>();
936 } else {
937 throw bad_result_access<std::remove_cvref_t<E>>(
938 std::move(*this).res_()[index<1>]);
939 }
940 }
941 return std::move(*this).res_()[index<0>];
942 }
943
944 /// @brief Accesses the error value contained in the @ref result
945 ///
946 /// @details
947 /// This function does not check if the @ref result contains an ok value.
948 /// Use of this function when the @ref result contains an error results in
949 /// undefined behavior.
950 ///
951 /// ## Example
952 /// ```
953 /// result<int, std::string> res{in_place_error, "oh no"};
954 ///
955 /// assert(res.error() == "oh no");
956 /// ```
957 22 [[nodiscard]] constexpr error_reference error() & noexcept { return res_()[index<1>]; }
958
959 /// @brief Accesses the error value contained in the @ref result
960 ///
961 /// @details
962 /// This function does not check if the @ref result contains an ok value.
963 /// Use of this function when the @ref result contains an error results in
964 /// undefined behavior.
965 ///
966 /// ## Example
967 /// ```
968 /// const result<int, std::string> res{in_place_error, "oh no"};
969 ///
970 /// assert(res.error() == "oh no");
971 /// ```
972 10 [[nodiscard]] constexpr error_const_reference error() const& noexcept {
973 10 return res_()[index<1>];
974 }
975
976 /// @brief Accesses the error value contained in the @ref result
977 ///
978 /// @details
979 /// This function does not check if the @ref result contains an ok value.
980 /// Use of this function when the @ref result contains an error results in
981 /// undefined behavior.
982 ///
983 /// ## Example
984 /// ```
985 /// result<int, std::string> res{in_place_error, "oh no"};
986 ///
987 /// assert(std::move(res).error() == "oh no");
988 /// ```
989 [[nodiscard]] constexpr error_rvalue_reference error() && {
990 return std::move(*this).res_()[index<1>];
991 }
992
993 /// @brief Accesses the error value contained in the @ref result
994 ///
995 /// @details
996 /// This function does not check if the @ref result contains an ok value.
997 /// Use of this function when the @ref result contains an error results in
998 /// undefined behavior.
999 ///
1000 /// ## Example
1001 /// ```
1002 /// const result<int, std::string> res{in_place_error, "oh no"};
1003 ///
1004 /// assert(std::move(res).error() == "oh no");
1005 /// ```
1006 [[nodiscard]] constexpr error_const_rvalue_reference error() const&& {
1007 return std::move(*this).res_()[index<1>];
1008 }
1009
1010 /// @brief Extracts the error in order to propagate it
1011 ///
1012 /// @details
1013 /// This function returns the error value by itself. This
1014 /// value can then be converted into a different result type for the
1015 /// purpose of propagating the error.
1016 ///
1017 /// This function does not check if the @ref result contains an ok value.
1018 /// Use of this function when the @ref result contains an error results in
1019 /// undefined behavior.
1020 ///
1021 /// ## Example
1022 /// ```
1023 /// result<void, std::string> func() {
1024 /// result<int, std::string> res{in_place_error, "oh no"};
1025 ///
1026 /// return res.prop_error();
1027 /// }
1028 /// ```
1029 [[nodiscard]] constexpr result<never, E> prop_error() const& {
1030 return result<never, E>{in_place_error, error()};
1031 }
1032
1033 /// @brief Extracts the error in order to propagate it
1034 ///
1035 /// @details
1036 /// This function returns the error value by itself. This
1037 /// value can then be converted into a different result type for the
1038 /// purpose of propagating the error.
1039 ///
1040 /// This function does not check if the @ref result contains an ok value.
1041 /// Use of this function when the @ref result contains an error results in
1042 /// undefined behavior.
1043 ///
1044 /// ## Example
1045 /// ```
1046 /// result<void, std::string> func() {
1047 /// result<int, std::string> res{in_place_error, "oh no"};
1048 ///
1049 /// return std::move(res).prop_error();
1050 /// }
1051 /// ```
1052 [[nodiscard]] constexpr result<never, E> prop_error() && {
1053 return result<never, E>{in_place_error, std::move(*this).error()};
1054 }
1055
1056 /// @brief Gets the ok value, or a default if the @ref result is an error
1057 ///
1058 /// @details
1059 /// If the @ref result contains an ok value, a copy of that ok value is
1060 /// returned. If the @ref result contains an error value, the provided
1061 /// default value is forwarded, cast, and returned as by the following:
1062 /// `static_cast<T>(std::forward<U>(default_value))`.
1063 ///
1064 /// ## Example
1065 /// ```
1066 /// result<int, std::string> res1{42};
1067 /// result<int, std::string> res2{in_place_error, "oh no"};
1068 ///
1069 /// assert(res1.value_or(0) == 42);
1070 ///
1071 /// assert(res2.value_or(0) == 0);
1072 /// ```
1073 template <typename U>
1074 6 [[nodiscard]] constexpr value_type value_or(U&& default_value) const& {
1075
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 1 times.
6 if (res_().index() == 0) {
1076 4 return res_()[index<0>];
1077 } else {
1078 2 return static_cast<value_type>(std::forward<U>(default_value));
1079 }
1080 }
1081
1082 /// @brief Gets the ok value, or a default if the @ref result is an error
1083 ///
1084 /// @details
1085 /// If the @ref result contains an ok value, that ok value is
1086 /// returned. If the @ref result contains an error value, the provided
1087 /// default value is forwarded, cast, and returned as by the following:
1088 /// `static_cast<T>(std::forward<U>(default_value))`.
1089 ///
1090 /// ## Example
1091 /// ```
1092 /// result<int, std::string> res1{42};
1093 /// result<int, std::string> res2{in_place_error, "oh no"};
1094 ///
1095 /// assert(std::move(res1).value_or(0) == 42);
1096 ///
1097 /// assert(std::move(res2).value_or(0) == 0);
1098 /// ```
1099 template <typename U>
1100 [[nodiscard]] constexpr value_type value_or(U&& default_value) && {
1101 if (res_().index() == 0) {
1102 return std::move(*this).res_()[index<0>];
1103 } else {
1104 return static_cast<value_type>(std::forward<U>(default_value));
1105 }
1106 }
1107
1108 /// @brief Gets the ok value, or returns the result of a callable
1109 ///
1110 /// @details
1111 /// If the @ref result contains an ok value, a copy of that ok value is
1112 /// returned. If the @ref result contains an error, the provided callable
1113 /// is invoked and the result is cast and returned, as if by:
1114 /// `static_cast<T>(std::invoke(std::forward<F>(f)))`.
1115 ///
1116 /// ## Example
1117 /// ```
1118 /// result<int, std::string> res1{42};
1119 /// result<int, std::string> res2{in_place_error, "oh no"};
1120 ///
1121 /// assert(res1.value_or_else([] { return 0; }) == 42);
1122 ///
1123 /// assert(res2.value_or_else({] { return 0; }) == 0);
1124 /// ```
1125 template <typename F>
1126 8 [[nodiscard]] constexpr value_type value_or_else(F&& f) const& {
1127
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
8 if (res_().index() == 0) {
1128 4 return res_()[index<0>];
1129 } else {
1130 4 return static_cast<T>(invoke(std::forward<F>(f)));
1131 }
1132 }
1133
1134 /// @brief Gets the ok value, or returns the result of a callable
1135 ///
1136 /// @details
1137 /// If the @ref result contains an ok value, a copy of that ok value is
1138 /// returned. If the @ref result contains an error, the provided callable
1139 /// is invoked and the result is cast and returned, as if by:
1140 /// `static_cast<T>(std::invoke(std::forward<F>(f)))`.
1141 ///
1142 /// ## Example
1143 /// ```
1144 /// result<int, std::string> res1{42};
1145 /// result<int, std::string> res2{in_place_error, "oh no"};
1146 ///
1147 /// assert(std::move(res1).value_or_else([] { return 0; }) == 42);
1148 ///
1149 /// assert(std::move(res2).value_or_else({] { return 0; }) == 0);
1150 /// ```
1151 template <typename F>
1152 [[nodiscard]] constexpr value_type value_or_else(F&& f) && {
1153 if (res_().index() == 0) {
1154 return std::move(*this).res_()[index<0>];
1155 } else {
1156 return static_cast<T>(invoke(std::forward<F>(f)));
1157 }
1158 }
1159
1160 /// @brief Accesses the ok value contained in the @ref result
1161 ///
1162 /// @details
1163 /// This function first checks if the @ref result contains an ok value
1164 /// before attempting to access the value. If the @ref result contains an
1165 /// error, then this function throws an exception.
1166 ///
1167 /// ## Example
1168 /// ```
1169 /// result<int, std::string> res{42};
1170 ///
1171 /// assert(res.ok() == 42);
1172 /// ```
1173 ///
1174 /// @throws bad_result_access Thrown if the @ref result contains an error
1175 [[nodiscard]] constexpr reference ok() & { return value(); }
1176
1177 /// @brief Accesses the ok value contained in the @ref result
1178 ///
1179 /// @details
1180 /// This function first checks if the @ref result contains an ok value
1181 /// before attempting to access the value. If the @ref result contains an
1182 /// error, then this function throws an exception.
1183 ///
1184 /// ## Example
1185 /// ```
1186 /// const result<int, std::string> res{42};
1187 ///
1188 /// assert(res.ok() == 42);
1189 /// ```
1190 ///
1191 /// @throws bad_result_access Thrown if the @ref result contains an error
1192 [[nodiscard]] constexpr const_reference ok() const& { return value(); }
1193
1194 /// @brief Accesses the ok value contained in the @ref result
1195 ///
1196 /// @details
1197 /// This function first checks if the @ref result contains an ok value
1198 /// before attempting to access the value. If the @ref result contains an
1199 /// error, then this function throws an exception.
1200 ///
1201 /// ## Example
1202 /// ```
1203 /// result<int, std::string> res{42};
1204 ///
1205 /// assert(std::move(res).ok() == 42);
1206 /// ```
1207 ///
1208 /// @throws bad_result_access Thrown if the @ref result contains an error
1209 [[nodiscard]] constexpr rvalue_reference ok() && { return std::move(*this).value(); }
1210
1211 /// @brief Accesses the ok value contained in the @ref result
1212 ///
1213 /// @details
1214 /// This function first checks if the @ref result contains an ok value
1215 /// before attempting to access the value. If the @ref result contains an
1216 /// error, then this function throws an exception.
1217 ///
1218 /// ## Example
1219 /// ```
1220 /// const result<int, std::string> res{42};
1221 ///
1222 /// assert(std::move(res).ok() == 42);
1223 /// ```
1224 ///
1225 /// @throws bad_result_access Thrown if the @ref result contains an error
1226 [[nodiscard]] constexpr rvalue_reference ok() const&& {
1227 return std::move(*this).value();
1228 }
1229
1230 /// @brief Gets the ok value, or a default if the @ref result is an error
1231 ///
1232 /// @details
1233 /// If the @ref result contains an ok value, a copy of that ok value is
1234 /// returned. If the @ref result contains an error value, the provided
1235 /// default value is forwarded, cast, and returned as by the following:
1236 /// `static_cast<T>(std::forward<U>(default_value))`.
1237 ///
1238 /// ## Example
1239 /// ```
1240 /// result<int, std::string> res1{42};
1241 /// result<int, std::string> res2{in_place_error, "oh no"};
1242 ///
1243 /// assert(res1.ok_or(0) == 42);
1244 ///
1245 /// assert(res2.ok_or(0) == 0);
1246 /// ```
1247 template <typename U>
1248 [[nodiscard]] constexpr value_type ok_or(U&& default_value) const& {
1249 return value_or(std::forward<U>(default_value));
1250 }
1251
1252 /// @brief Gets the ok value, or a default if the @ref result is an error
1253 ///
1254 /// @details
1255 /// If the @ref result contains an ok value, that ok value is
1256 /// returned. If the @ref result contains an error value, the provided
1257 /// default value is forwarded, cast, and returned as by the following:
1258 /// `static_cast<T>(std::forward<U>(default_value))`.
1259 ///
1260 /// ## Example
1261 /// ```
1262 /// result<int, std::string> res1{42};
1263 /// result<int, std::string> res2{in_place_error, "oh no"};
1264 ///
1265 /// assert(std::move(res1).ok_or(0) == 42);
1266 ///
1267 /// assert(std::move(res2).ok_or(0) == 0);
1268 /// ```
1269 template <typename U>
1270 [[nodiscard]] constexpr value_type ok_or(U&& default_value) && {
1271 return std::move(*this).ok_or(std::forward<U>(default_value));
1272 }
1273
1274 /// @brief Gets the ok value, or returns the result of a callable
1275 ///
1276 /// @details
1277 /// If the @ref result contains an ok value, a copy of that ok value is
1278 /// returned. If the @ref result contains an error, the provided callable
1279 /// is invoked and the result is cast and returned, as if by:
1280 /// `static_cast<T>(std::invoke(std::forward<F>(f)))`.
1281 ///
1282 /// ## Example
1283 /// ```
1284 /// result<int, std::string> res1{42};
1285 /// result<int, std::string> res2{in_place_error, "oh no"};
1286 ///
1287 /// assert(res1.ok_or_else([] { return 0; }) == 42);
1288 ///
1289 /// assert(res2.ok_or_else({] { return 0; }) == 0);
1290 /// ```
1291 template <typename F>
1292 [[nodiscard]] constexpr value_type ok_or_else(F&& f) const& {
1293 return value_or_else(std::forward<F>(f));
1294 }
1295
1296 /// @brief Gets the ok value, or returns the result of a callable
1297 ///
1298 /// @details
1299 /// If the @ref result contains an ok value, a copy of that ok value is
1300 /// returned. If the @ref result contains an error, the provided callable
1301 /// is invoked and the result is cast and returned, as if by:
1302 /// `static_cast<T>(std::invoke(std::forward<F>(f)))`.
1303 ///
1304 /// ## Example
1305 /// ```
1306 /// result<int, std::string> res1{42};
1307 /// result<int, std::string> res2{in_place_error, "oh no"};
1308 ///
1309 /// assert(std::move(res1).ok_or_else([] { return 0; }) == 42);
1310 ///
1311 /// assert(std::move(res2).ok_or_else({] { return 0; }) == 0);
1312 /// ```
1313 template <typename F>
1314 [[nodiscard]] constexpr value_type ok_or_else(F&& f) && {
1315 return std::move(*this).value_or_else(std::forward<F>(f));
1316 }
1317
1318 /// @brief Applies a callable to the contents of a @ref result
1319 ///
1320 /// @details
1321 /// If the @ref result contains an ok value, the value is passed into the
1322 /// callable, and the result of invoking the callable is returned from this
1323 /// function. If the @ref result contains an error, the callable is not
1324 /// invoked, and a copy of the error is returned.
1325 ///
1326 /// This function only participates in overload resultion if the result of
1327 /// invoking the callable is a @ref result.
1328 ///
1329 /// ## Example
1330 /// ```
1331 /// result<int, std::string> res1{42};
1332 /// result<int, std::string> res2{-42};
1333 /// result<int, std::string> res3{in_place_error, "oh no"};
1334 ///
1335 /// auto callable = [](int value) -> result<unsigned int, const char*> {
1336 /// if (value < 0) {
1337 /// return error<const char*>("negaive value");
1338 /// } else {
1339 /// return static_cast<unsigned int>(value);
1340 /// }
1341 /// };
1342 ///
1343 /// auto res1_new = res1.and_then(callable);
1344 /// auto res2_new = res2.and_then(callable);
1345 /// auto res3_new = res3.and_then(callable);
1346 ///
1347 /// assert(res1_new.is_ok());
1348 /// assert(*res1_new == 42);
1349 ///
1350 /// assert(res2_new.is_error());
1351 /// assert(res2_new.error() == "negative value");
1352 ///
1353 /// assert(res3_new.is_error());
1354 /// assert(res3_new.error() == "oh no");
1355 /// ```
1356 template <typename F>
1357 constexpr auto and_then(F&& f) &
1358 #ifndef DOXYGEN
1359 requires(
1360 detail::is_result_v<std::remove_cvref_t<detail::invoke_result_t<F, reference>>>)
1361 #endif
1362 {
1363 if constexpr (std::is_void_v<T>) {
1364 if (res_().index() == 0) {
1365 return std::invoke(std::forward<F>(f), void_v);
1366 } else {
1367 if constexpr (std::is_void_v<E>) {
1368 return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{
1369 in_place_error};
1370 } else {
1371 return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{
1372 in_place_error, res_()[index<1>]};
1373 }
1374 }
1375 } else {
1376 if (res_().index() == 0) {
1377 return std::invoke(std::forward<F>(f), res_()[index<0>]);
1378 } else {
1379 if constexpr (std::is_void_v<E>) {
1380 return std::remove_cvref_t<std::invoke_result_t<F, reference>>{
1381 in_place_error};
1382 } else {
1383 return std::remove_cvref_t<std::invoke_result_t<F, reference>>{
1384 in_place_error, res_()[index<1>]};
1385 }
1386 }
1387 }
1388 }
1389
1390 /// @brief Applies a callable to the contents of a @ref result
1391 ///
1392 /// @details
1393 /// If the @ref result contains an ok value, the value is passed into the
1394 /// callable, and the result of invoking the callable is returned from this
1395 /// function. If the @ref result contains an error, the callable is not
1396 /// invoked, and a copy of the error is returned.
1397 ///
1398 /// This function only participates in overload resultion if the result of
1399 /// invoking the callable is a @ref result.
1400 ///
1401 /// ## Example
1402 /// ```
1403 /// const result<int, std::string> res1{42};
1404 /// const result<int, std::string> res2{-42};
1405 /// const result<int, std::string> res3{in_place_error, "oh no"};
1406 ///
1407 /// auto callable = [](int value) -> result<unsigned int, const char*> {
1408 /// if (value < 0) {
1409 /// return error<const char*>("negaive value");
1410 /// } else {
1411 /// return static_cast<unsigned int>(value);
1412 /// }
1413 /// };
1414 ///
1415 /// auto res1_new = res1.and_then(callable);
1416 /// auto res2_new = res2.and_then(callable);
1417 /// auto res3_new = res3.and_then(callable);
1418 ///
1419 /// assert(res1_new.is_ok());
1420 /// assert(*res1_new == 42);
1421 ///
1422 /// assert(res2_new.is_error());
1423 /// assert(res2_new.error() == "negative value");
1424 ///
1425 /// assert(res3_new.is_error());
1426 /// assert(res3_new.error() == "oh no");
1427 /// ```
1428 template <typename F>
1429 8 constexpr auto and_then(F&& f) const& {
1430 if constexpr (std::is_void_v<T>) {
1431
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 2 times.
6 if (res_().index() == 0) {
1432 2 return std::invoke(std::forward<F>(f), void_v);
1433 } else {
1434 if constexpr (std::is_void_v<E>) {
1435 return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{
1436 2 in_place_error};
1437 } else {
1438 return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{
1439 2 in_place_error, res_()[index<1>]};
1440 }
1441 }
1442 } else {
1443
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
2 if (res_().index() == 0) {
1444 2 return std::invoke(std::forward<F>(f), res_()[index<0>]);
1445 } else {
1446 if constexpr (std::is_void_v<E>) {
1447 return std::remove_cvref_t<std::invoke_result_t<F, const_reference>>{
1448 in_place_error};
1449 } else {
1450 return std::remove_cvref_t<std::invoke_result_t<F, const_reference>>{
1451 in_place_error, res_()[index<1>]};
1452 }
1453 }
1454 }
1455 }
1456
1457 /// @brief Applies a callable to the contents of a @ref result
1458 ///
1459 /// @details
1460 /// If the @ref result contains an ok value, the value is passed into the
1461 /// callable, and the result of invoking the callable is returned from this
1462 /// function. If the @ref result contains an error, the callable is not
1463 /// invoked, the error is returned.
1464 ///
1465 /// This function only participates in overload resultion if the result of
1466 /// invoking the callable is a @ref result.
1467 ///
1468 /// ## Example
1469 /// ```
1470 /// result<int, std::string> res1{42};
1471 /// result<int, std::string> res2{-42};
1472 /// result<int, std::string> res3{in_place_error, "oh no"};
1473 ///
1474 /// auto callable = [](int value) -> result<unsigned int, const char*> {
1475 /// if (value < 0) {
1476 /// return error<const char*>("negaive value");
1477 /// } else {
1478 /// return static_cast<unsigned int>(value);
1479 /// }
1480 /// };
1481 ///
1482 /// auto res1_new = std::move(res1).and_then(callable);
1483 /// auto res2_new = std::move(res2).and_then(callable);
1484 /// auto res3_new = std::move(res3).and_then(callable);
1485 ///
1486 /// assert(res1_new.is_ok());
1487 /// assert(*res1_new == 42);
1488 ///
1489 /// assert(res2_new.is_error());
1490 /// assert(res2_new.error() == "negative value");
1491 ///
1492 /// assert(res3_new.is_error());
1493 /// assert(res3_new.error() == "oh no");
1494 /// ```
1495 template <typename F>
1496 constexpr auto and_then(F&& f) && {
1497 if constexpr (std::is_void_v<T>) {
1498 if (res_().index() == 0) {
1499 return std::invoke(std::forward<F>(f), void_v);
1500 } else {
1501 if constexpr (std::is_void_v<E>) {
1502 return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{
1503 in_place_error};
1504 } else {
1505 return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{
1506 in_place_error, std::move(*this).res_()[index<1>]};
1507 }
1508 }
1509 } else {
1510 if (res_().index() == 0) {
1511 return std::invoke(std::forward<F>(f), std::move(*this).res_()[index<0>]);
1512 } else {
1513 if constexpr (std::is_void_v<E>) {
1514 return std::remove_cvref_t<std::invoke_result_t<F, rvalue_reference>>{
1515 in_place_error};
1516 } else {
1517 return std::remove_cvref_t<std::invoke_result_t<F, rvalue_reference>>{
1518 in_place_error, std::move(*this).res_()[index<1>]};
1519 }
1520 }
1521 }
1522 }
1523
1524 /// @brief Applies a callable to the contents of a @ref result
1525 ///
1526 /// @details
1527 /// If the @ref result contains an ok value, the value is passed into the
1528 /// callable, and the result of invoking the callable is returned from this
1529 /// function. If the @ref result contains an error, the callable is not
1530 /// invoked, the error is returned.
1531 ///
1532 /// This function only participates in overload resultion if the result of
1533 /// invoking the callable is a @ref result.
1534 ///
1535 /// ## Example
1536 /// ```
1537 /// const result<int, std::string> res1{42};
1538 /// const result<int, std::string> res2{-42};
1539 /// const result<int, std::string> res3{in_place_error, "oh no"};
1540 ///
1541 /// auto callable = [](int value) -> result<unsigned int, const char*> {
1542 /// if (value < 0) {
1543 /// return error<const char*>("negaive value");
1544 /// } else {
1545 /// return static_cast<unsigned int>(value);
1546 /// }
1547 /// };
1548 ///
1549 /// auto res1_new = std::move(res1).and_then(callable);
1550 /// auto res2_new = std::move(res2).and_then(callable);
1551 /// auto res3_new = std::move(res3).and_then(callable);
1552 ///
1553 /// assert(res1_new.is_ok());
1554 /// assert(*res1_new == 42);
1555 ///
1556 /// assert(res2_new.is_error());
1557 /// assert(res2_new.error() == "negative value");
1558 ///
1559 /// assert(res3_new.is_error());
1560 /// assert(res3_new.error() == "oh no");
1561 /// ```
1562 template <typename F>
1563 constexpr auto and_then(F&& f) const&& {
1564 if constexpr (std::is_void_v<T>) {
1565 if (res_().index() == 0) {
1566 return std::invoke(std::forward<F>(f), void_v);
1567 } else {
1568 if constexpr (std::is_void_v<E>) {
1569 return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{
1570 in_place_error};
1571 } else {
1572 return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{
1573 in_place_error, std::move(*this).res_()[index<1>]};
1574 }
1575 }
1576 } else {
1577 if (res_().index() == 0) {
1578 return std::invoke(std::forward<F>(f), std::move(*this).res_()[index<0>]);
1579 } else {
1580 if constexpr (std::is_void_v<E>) {
1581 return std::remove_cvref_t<
1582 std::invoke_result_t<F, const_rvalue_reference>>{in_place_error};
1583 } else {
1584 return std::remove_cvref_t<
1585 std::invoke_result_t<F, const_rvalue_reference>>{
1586 in_place_error, std::move(*this).res_()[index<1>]};
1587 }
1588 }
1589 }
1590 }
1591
1592 /// @brief Perforams a transformation on the ok value of a @ref result
1593 ///
1594 /// @details
1595 /// If the @ref result contains an ok value, that value is passed to the
1596 /// transformation callable provided. The value returned from the callable
1597 /// is then returned from this function as the ok value of a new @ref
1598 /// result, where ok type of the new result is the exact type returned
1599 /// from the callable. If the @ref result contains an error value, a copy
1600 /// of the error is returned.
1601 ///
1602 /// Note that this function is identical to @ref map, but the name
1603 /// `transform` makes @ref result able to be a drop in replacement for
1604 /// `std::expected`. `map` is the more typical name of this monadic
1605 /// operation outside of C++.
1606 ///
1607 /// ## Example
1608 /// ```
1609 /// result<int, std::string> res1{42};
1610 /// result<int, std::string> res2{in_place_error, "oh no"};
1611 ///
1612 /// auto res1_mapped = res1.transform([](auto value) {
1613 /// return std::to_string(value);
1614 /// });
1615 /// auto res2_mapped = res2.transform([](auto value) {
1616 /// return std::to_string(value);
1617 /// });
1618 ///
1619 /// assert(res1_mapped.is_error());
1620 /// assert(res1_mapped.error() == "oh no");
1621 ///
1622 /// assert(res2_mapped.is_ok());
1623 /// assert(*res2_mapped == "42");
1624 /// ```
1625 template <typename F>
1626 constexpr auto transform(F&& f) & {
1627 if constexpr (std::is_void_v<T>) {
1628 using res_t = std::invoke_result_t<F, void_t>;
1629 if (res_().index() == 0) {
1630 if constexpr (std::is_void_v<res_t>) {
1631 std::invoke(std::forward<F>(f), void_v);
1632 return result<res_t, E>{std::in_place};
1633 } else {
1634 return result<res_t, E>{std::in_place,
1635 std::invoke(std::forward<F>(f), void_v)};
1636 }
1637 } else {
1638 if constexpr (std::is_void_v<E>) {
1639 return result<res_t, E>{in_place_error};
1640 } else {
1641 return result<res_t, E>{in_place_error, res_()[index<1>]};
1642 }
1643 }
1644 } else {
1645 using res_t = std::invoke_result_t<F, reference>;
1646 if (res_().index() == 0) {
1647 if constexpr (std::is_void_v<res_t>) {
1648 std::invoke(std::forward<F>(f), res_()[index<0>]);
1649 return result<res_t, E>{std::in_place};
1650 } else {
1651 return result<res_t, E>{
1652 std::in_place, std::invoke(std::forward<F>(f), res_()[index<0>])};
1653 }
1654 } else {
1655 if constexpr (std::is_void_v<E>) {
1656 return result<res_t, E>{in_place_error};
1657 } else {
1658 return result<res_t, E>{in_place_error, res_()[index<1>]};
1659 }
1660 }
1661 }
1662 }
1663
1664 /// @brief Perforams a transformation on the ok value of a @ref result
1665 ///
1666 /// @details
1667 /// If the @ref result contains an ok value, that value is passed to the
1668 /// transformation callable provided. The value returned from the callable
1669 /// is then returned from this function as the ok value of a new @ref
1670 /// result, where ok type of the new result is the exact type returned
1671 /// from the callable. If the @ref result contains an error value, a copy
1672 /// of the error is returned.
1673 ///
1674 /// Note that this function is identical to @ref map, but the name
1675 /// `transform` makes @ref result able to be a drop in replacement for
1676 /// `std::expected`. `map` is the more typical name of this monadic
1677 /// operation outside of C++.
1678 ///
1679 /// ## Example
1680 /// ```
1681 /// const result<int, std::string> res1{42};
1682 /// const result<int, std::string> res2{in_place_error, "oh no"};
1683 ///
1684 /// auto res1_mapped = res1.transform([](auto value) {
1685 /// return std::to_string(value);
1686 /// });
1687 /// auto res2_mapped = res2.transform([](auto value) {
1688 /// return std::to_string(value);
1689 /// });
1690 ///
1691 /// assert(res1_mapped.is_error());
1692 /// assert(res1_mapped.error() == "oh no");
1693 ///
1694 /// assert(res2_mapped.is_ok());
1695 /// assert(*res2_mapped == "42");
1696 /// ```
1697 template <typename F>
1698 8 constexpr auto transform(F&& f) const& {
1699 if constexpr (std::is_void_v<T>) {
1700 using res_t = std::invoke_result_t<F, void_t>;
1701
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 2 times.
6 if (res_().index() == 0) {
1702 if constexpr (std::is_void_v<res_t>) {
1703 std::invoke(std::forward<F>(f), void_v);
1704 return result<res_t, E>{std::in_place};
1705 } else {
1706 return result<res_t, E>{std::in_place,
1707
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
4 std::invoke(std::forward<F>(f), void_v)};
1708 }
1709 } else {
1710 if constexpr (std::is_void_v<E>) {
1711 2 return result<res_t, E>{in_place_error};
1712 } else {
1713 2 return result<res_t, E>{in_place_error, res_()[index<1>]};
1714 }
1715 }
1716 } else {
1717 using res_t = std::invoke_result_t<F, const_reference>;
1718
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
2 if (res_().index() == 0) {
1719 if constexpr (std::is_void_v<res_t>) {
1720 std::invoke(std::forward<F>(f), res_()[index<0>]);
1721 return result<res_t, E>{std::in_place};
1722 } else {
1723 return result<res_t, E>{
1724
1/2
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
4 std::in_place, std::invoke(std::forward<F>(f), res_()[index<0>])};
1725 }
1726 } else {
1727 if constexpr (std::is_void_v<E>) {
1728 return result<res_t, E>{in_place_error};
1729 } else {
1730 return result<res_t, E>{in_place_error, res_()[index<1>]};
1731 }
1732 }
1733 }
1734 }
1735
1736 /// @brief Perforams a transformation on the ok value of a @ref result
1737 ///
1738 /// @details
1739 /// If the @ref result contains an ok value, that value is passed to the
1740 /// transformation callable provided. The value returned from the callable
1741 /// is then returned from this function as the ok value of a new @ref
1742 /// result, where ok type of the new result is the exact type returned
1743 /// from the callable. If the @ref result contains an error value, the
1744 /// error is returned.
1745 ///
1746 /// Note that this function is identical to @ref map, but the name
1747 /// `transform` makes @ref result able to be a drop in replacement for
1748 /// `std::expected`. `map` is the more typical name of this monadic
1749 /// operation outside of C++.
1750 ///
1751 /// ## Example
1752 /// ```
1753 /// result<int, std::string> res1{42};
1754 /// result<int, std::string> res2{in_place_error, "oh no"};
1755 ///
1756 /// auto res1_mapped = std::move(res1).transform([](auto value) {
1757 /// return std::to_string(value);
1758 /// });
1759 /// auto res2_mapped = std::move(res2).transform([](auto value) {
1760 /// return std::to_string(value);
1761 /// });
1762 ///
1763 /// assert(res1_mapped.is_error());
1764 /// assert(res1_mapped.error() == "oh no");
1765 ///
1766 /// assert(res2_mapped.is_ok());
1767 /// assert(*res2_mapped == "42");
1768 /// ```
1769 template <typename F>
1770 constexpr auto transform(F&& f) && {
1771 if constexpr (std::is_void_v<T>) {
1772 using res_t = std::invoke_result_t<F, void_t>;
1773 if (res_().index() == 0) {
1774 if constexpr (std::is_void_v<res_t>) {
1775 std::invoke(std::forward<F>(f), void_v);
1776 return result<res_t, E>{std::in_place};
1777 } else {
1778 return result<res_t, E>{std::in_place,
1779 std::invoke(std::forward<F>(f), void_v)};
1780 }
1781 } else {
1782 if constexpr (std::is_void_v<E>) {
1783 return result<res_t, E>{in_place_error};
1784 } else {
1785 return result<res_t, E>{in_place_error,
1786 std::move(*this).res_()[index<1>]};
1787 }
1788 }
1789 } else {
1790 using res_t = std::invoke_result_t<F, rvalue_reference>;
1791 if (res_().index() == 0) {
1792 if constexpr (std::is_void_v<res_t>) {
1793 std::invoke(std::forward<F>(f), std::move(*this).res_()[index<0>]);
1794 return result<res_t, E>{std::in_place};
1795 } else {
1796 return result<res_t, E>{
1797 std::in_place,
1798 std::invoke(std::forward<F>(f), std::move(*this).res_()[index<0>])};
1799 }
1800 } else {
1801 if constexpr (std::is_void_v<E>) {
1802 return result<res_t, E>{in_place_error};
1803 } else {
1804 return result<res_t, E>{in_place_error,
1805 std::move(*this).res_()[index<1>]};
1806 }
1807 }
1808 }
1809 }
1810
1811 /// @brief Perforams a transformation on the ok value of a @ref result
1812 ///
1813 /// @details
1814 /// If the @ref result contains an ok value, that value is passed to the
1815 /// transformation callable provided. The value returned from the callable
1816 /// is then returned from this function as the ok value of a new @ref
1817 /// result, where ok type of the new result is the exact type returned
1818 /// from the callable. If the @ref result contains an error value, the
1819 /// error is returned.
1820 ///
1821 /// Note that this function is identical to @ref map, but the name
1822 /// `transform` makes @ref result able to be a drop in replacement for
1823 /// `std::expected`. `map` is the more typical name of this monadic
1824 /// operation outside of C++.
1825 ///
1826 /// ## Example
1827 /// ```
1828 /// const result<int, std::string> res1{42};
1829 /// const result<int, std::string> res2{in_place_error, "oh no"};
1830 ///
1831 /// auto res1_mapped = std::move(res1).transform([](auto value) {
1832 /// return std::to_string(value);
1833 /// });
1834 /// auto res2_mapped = std::move(res2).transform([](auto value) {
1835 /// return std::to_string(value);
1836 /// });
1837 ///
1838 /// assert(res1_mapped.is_error());
1839 /// assert(res1_mapped.error() == "oh no");
1840 ///
1841 /// assert(res2_mapped.is_ok());
1842 /// assert(*res2_mapped == "42");
1843 /// ```
1844 template <typename F>
1845 constexpr auto transform(F&& f) const&& {
1846 if constexpr (std::is_void_v<T>) {
1847 using res_t = std::invoke_result_t<F, void_t>;
1848 if (res_().index() == 0) {
1849 if constexpr (std::is_void_v<res_t>) {
1850 std::invoke(std::forward<F>(f), void_v);
1851 return result<res_t, E>{std::in_place};
1852 } else {
1853 return result<res_t, E>{std::in_place,
1854 std::invoke(std::forward<F>(f), void_v)};
1855 }
1856 } else {
1857 if constexpr (std::is_void_v<E>) {
1858 return result<res_t, E>{in_place_error};
1859 } else {
1860 return result<res_t, E>{in_place_error,
1861 std::move(*this).res_()[index<1>]};
1862 }
1863 }
1864 } else {
1865 using res_t = std::invoke_result_t<F, const_rvalue_reference>;
1866 if (res_().index() == 0) {
1867 if constexpr (std::is_void_v<res_t>) {
1868 std::invoke(std::forward<F>(f), std::move(*this).res_()[index<0>]);
1869 return result<res_t, E>{std::in_place};
1870 } else {
1871 return result<res_t, E>{
1872 std::in_place,
1873 std::invoke(std::forward<F>(f), std::move(*this).res_()[index<0>])};
1874 }
1875 } else {
1876 if constexpr (std::is_void_v<E>) {
1877 return result<res_t, E>{in_place_error};
1878 } else {
1879 return result<res_t, E>{in_place_error,
1880 std::move(*this).res_()[index<1>]};
1881 }
1882 }
1883 }
1884 }
1885
1886 /// @brief Perforams a transformation on the ok value of a @ref result
1887 ///
1888 /// @details
1889 /// If the @ref result contains an ok value, that value is passed to the
1890 /// transformation callable provided. The value returned from the callable
1891 /// is then returned from this function as the ok value of a new @ref
1892 /// result, where ok type of the new result is the exact type returned
1893 /// from the callable. If the @ref result contains an error value, a copy
1894 /// of the error is returned.
1895 ///
1896 /// Note that this function is idential to @ref transform, but the name
1897 /// `map` is the more typical name of this monadic operation outside of
1898 /// C++.
1899 ///
1900 /// ## Example
1901 /// ```
1902 /// result<int, std::string> res1{42};
1903 /// result<int, std::string> res2{in_place_error, "oh no"};
1904 ///
1905 /// auto res1_mapped = res1.map([](auto value) {
1906 /// return std::to_string(value);
1907 /// });
1908 /// auto res2_mapped = res2.map([](auto value) {
1909 /// return std::to_string(value);
1910 /// });
1911 ///
1912 /// assert(res1_mapped.is_error());
1913 /// assert(res1_mapped.error() == "oh no");
1914 ///
1915 /// assert(res2_mapped.is_ok());
1916 /// assert(*res2_mapped == "42");
1917 /// ```
1918 template <typename F>
1919 constexpr auto map(F&& f) & {
1920 return transform(std::forward<F>(f));
1921 }
1922
1923 /// @brief Perforams a transformation on the ok value of a @ref result
1924 ///
1925 /// @details
1926 /// If the @ref result contains an ok value, that value is passed to the
1927 /// transformation callable provided. The value returned from the callable
1928 /// is then returned from this function as the ok value of a new @ref
1929 /// result, where ok type of the new result is the exact type returned
1930 /// from the callable. If the @ref result contains an error value, a copy
1931 /// of the error is returned.
1932 ///
1933 /// Note that this function is idential to @ref transform, but the name
1934 /// `map` is the more typical name of this monadic operation outside of
1935 /// C++.
1936 ///
1937 /// ## Example
1938 /// ```
1939 /// const result<int, std::string> res1{42};
1940 /// const result<int, std::string> res2{in_place_error, "oh no"};
1941 ///
1942 /// auto res1_mapped = res1.map([](auto value) {
1943 /// return std::to_string(value);
1944 /// });
1945 /// auto res2_mapped = res2.map([](auto value) {
1946 /// return std::to_string(value);
1947 /// });
1948 ///
1949 /// assert(res1_mapped.is_error());
1950 /// assert(res1_mapped.error() == "oh no");
1951 ///
1952 /// assert(res2_mapped.is_ok());
1953 /// assert(*res2_mapped == "42");
1954 /// ```
1955 template <typename F>
1956 constexpr auto map(F&& f) const& {
1957 return transform(std::forward<F>(f));
1958 }
1959
1960 /// @brief Perforams a transformation on the ok value of a @ref result
1961 ///
1962 /// @details
1963 /// If the @ref result contains an ok value, that value is passed to the
1964 /// transformation callable provided. The value returned from the callable
1965 /// is then returned from this function as the ok value of a new @ref
1966 /// result, where ok type of the new result is the exact type returned
1967 /// from the callable. If the @ref result contains an error value, the
1968 /// error is returned.
1969 ///
1970 /// Note that this function is idential to @ref transform, but the name
1971 /// `map` is the more typical name of this monadic operation outside of
1972 /// C++.
1973 ///
1974 /// ## Example
1975 /// ```
1976 /// result<int, std::string> res1{42};
1977 /// result<int, std::string> res2{in_place_error, "oh no"};
1978 ///
1979 /// auto res1_mapped = std::move(res1).map([](auto value) {
1980 /// return std::to_string(value);
1981 /// });
1982 /// auto res2_mapped = std::move(res2).map([](auto value) {
1983 /// return std::to_string(value);
1984 /// });
1985 ///
1986 /// assert(res1_mapped.is_error());
1987 /// assert(res1_mapped.error() == "oh no");
1988 ///
1989 /// assert(res2_mapped.is_ok());
1990 /// assert(*res2_mapped == "42");
1991 /// ```
1992 template <typename F>
1993 constexpr auto map(F&& f) && {
1994 return std::move(*this).transform(std::forward<F>(f));
1995 }
1996
1997 /// @brief Perforams a transformation on the ok value of a @ref result
1998 ///
1999 /// @details
2000 /// If the @ref result contains an ok value, that value is passed to the
2001 /// transformation callable provided. The value returned from the callable
2002 /// is then returned from this function as the ok value of a new @ref
2003 /// result, where ok type of the new result is the exact type returned
2004 /// from the callable. If the @ref result contains an error value, the
2005 /// error is returned.
2006 ///
2007 /// Note that this function is idential to @ref transform, but the name
2008 /// `map` is the more typical name of this monadic operation outside of
2009 /// C++.
2010 ///
2011 /// ## Example
2012 /// ```
2013 /// const result<int, std::string> res1{42};
2014 /// const result<int, std::string> res2{in_place_error, "oh no"};
2015 ///
2016 /// auto res1_mapped = std::move(res1).map([](auto value) {
2017 /// return std::to_string(value);
2018 /// });
2019 /// auto res2_mapped = std::move(res2).map([](auto value) {
2020 /// return std::to_string(value);
2021 /// });
2022 ///
2023 /// assert(res1_mapped.is_error());
2024 /// assert(res1_mapped.error() == "oh no");
2025 ///
2026 /// assert(res2_mapped.is_ok());
2027 /// assert(*res2_mapped == "42");
2028 /// ```
2029 template <typename F>
2030 constexpr auto map(F&& f) const&& {
2031 return std::move(*this).transform(std::forward<F>(f));
2032 }
2033
2034 /// @brief Returns the result of invoking `f` if the @ref result is an error
2035 ///
2036 /// @details
2037 /// If the @ref result contains an ok value, a copy of the entire @ref
2038 /// result is returned. If the @ref result contains an error value, `f` is
2039 /// invoked with the error value as an argument, and the returned value
2040 /// from invoking `f` is returned from this function, converting to
2041 /// `result<T, E>` if necessary.
2042 ///
2043 /// ## Example
2044 /// ```
2045 /// result<int, std::string> res1{42};
2046 /// result<int, std::string> res2{in_place_error, "oh no"};
2047 ///
2048 /// auto res1_new = res1.or_else([]([[maybe_unused]] const auto& err) {
2049 /// return 0;
2050 /// });
2051 /// auto res2_new = res2.or_else([]([[maybe_unused]] const auto& err) {
2052 /// return 0;
2053 /// });
2054 ///
2055 /// assert(res1_new.is_ok());
2056 /// assert(*res1_new == 42);
2057 ///
2058 /// assert(res2_new.is_ok());
2059 /// assert(*res2_new == 0);
2060 /// ```
2061 template <typename F>
2062 8 constexpr result or_else(F&& f) const& {
2063
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
8 if (res_().index() == 0) {
2064 4 return *this;
2065 } else {
2066 if constexpr (std::is_void_v<E>) {
2067 2 return std::invoke(std::forward<F>(f), void_v);
2068 } else {
2069 2 return std::invoke(std::forward<F>(f), res_()[index<1>]);
2070 }
2071 }
2072 }
2073
2074 /// @brief Returns the result of invoking `f` if the @ref result is an error
2075 ///
2076 /// @details
2077 /// If the @ref result contains an ok value, the entire @ref
2078 /// result is returned. If the @ref result contains an error value, `f` is
2079 /// invoked with the error value as an argument, and the returned value
2080 /// from invoking `f` is returned from this function, converting to
2081 /// `result<T, E>` if necessary.
2082 ///
2083 /// ## Example
2084 /// ```
2085 /// result<int, std::string> res1{42};
2086 /// result<int, std::string> res2{in_place_error, "oh no"};
2087 ///
2088 /// auto res1_new = std::move(res1).or_else([]([[maybe_unused]] auto err) {
2089 /// return 0;
2090 /// });
2091 /// auto res2_new = std::move(res2).or_else([]([[maybe_unused]] auto err) {
2092 /// return 0;
2093 /// });
2094 ///
2095 /// assert(res1_new.is_ok());
2096 /// assert(*res1_new == 42);
2097 ///
2098 /// assert(res2_new.is_ok());
2099 /// assert(*res2_new == 0);
2100 /// ```
2101 template <typename F>
2102 constexpr result or_else(F&& f) && {
2103 if (res_().index() == 0) {
2104 return std::move(*this);
2105 } else {
2106 if constexpr (std::is_void_v<E>) {
2107 return std::invoke(std::forward<F>(f), void_v);
2108 } else {
2109 return std::invoke(std::forward<F>(f), std::move(res_()[index<1>]));
2110 }
2111 }
2112 }
2113
2114 /// @brief Converts `result<result<T, E1>, E2>` into `result<T, E3>`
2115 ///
2116 /// @details
2117 /// If the outer @ref result contains an error, a copy of that error is
2118 /// returned. If the outer @ref result contains an ok value, and the inner
2119 /// @ref result contains an error, a copy of that inner error is returned.
2120 /// If the outer @ref result contains an ok value and the inner @ref result
2121 /// contains an ok value, a copy of that inner ok value is returned.
2122 ///
2123 /// If the outer @ref result and the inner @ref result have different error
2124 /// types, the returned @ref result will be one of these two types based on
2125 /// the following priority rules:
2126 ///
2127 /// 1. If the outer error type is `void`, use the inner error type
2128 /// 2. Else, if the inner error type is `void`, use the outer error type
2129 /// 3. Else, if the outer error type is constructible from the inner error
2130 /// type, use the outer error type.
2131 /// 4. Else, if the inner error type is constructible from the outer error
2132 /// type, use the inner error type.
2133 ///
2134 /// Note that only one level of @ref result is removed. For example, a
2135 /// `result<result<result<T, E>, E>, E>` will flatten to a
2136 /// `result<result<T, E>, E>`.
2137 ///
2138 /// ## Example
2139 /// ```
2140 /// result<result<int, const char*>, std::string> res1{in_place, 42};
2141 /// result<result<int, const char*>, std::string> res2{
2142 /// in_place, in_place_error, "oh no"};
2143 /// result<result<int, const char*>, std::string> res3{
2144 /// in_place_error, "oh no"};
2145 ///
2146 /// result<int, std::string> res1_flat = res1.flatten();
2147 /// result<int, std::string> res2_flat = res2.flatten();
2148 /// result<int, std::string> res3_flat = res3.flatten();
2149 ///
2150 /// assert(res1_flat.is_ok());
2151 /// assert(*res1_flat == 42);
2152 ///
2153 /// assert(res2_flat.is_error());
2154 /// assert(res2_flat.error() == "oh no");
2155 ///
2156 /// assert(res3_flat.is_error());
2157 /// assert(res3_flat.error() == "oh no");
2158 /// ```
2159 [[nodiscard]] constexpr auto flatten() const&
2160 #ifndef DOXYGEN
2161 requires(detail::is_result_v<T>)
2162 #endif
2163 {
2164 if constexpr (std::is_void_v<typename T::error_type>) {
2165 using ret_t = result<typename T::value_type, E>;
2166 if (is_ok()) {
2167 return ret_t{res_()[index<0>]};
2168 } else {
2169 if constexpr (std::is_void_v<E>) {
2170 return ret_t{in_place_error};
2171 } else {
2172 return ret_t{in_place_error, error()};
2173 }
2174 }
2175 } else if constexpr (std::is_void_v<E>) {
2176 using ret_t = T;
2177 if (is_ok()) {
2178 return res_()[index<0>];
2179 } else {
2180 return ret_t{in_place_error, error()};
2181 }
2182 } else if constexpr (detail::traits<E>::template is_constructible<
2183 typename T::error_const_reference>) {
2184 using ret_t = result<typename T::value_type, E>;
2185 if (is_ok()) {
2186 return ret_t{res_()[index<0>]};
2187 } else {
2188 return ret_t{in_place_error, error()};
2189 }
2190 } else if constexpr (detail::traits<typename T::error_type>::
2191 template is_constructible<error_const_reference>) {
2192 using ret_t = T;
2193 if (is_ok()) {
2194 return res_()[index<0>];
2195 } else {
2196 return ret_t{in_place_error, error()};
2197 }
2198 }
2199 }
2200
2201 /// @brief Converts `result<result<T, E1>, E2>` into `result<T, E3>`
2202 ///
2203 /// @details
2204 /// If the outer @ref result contains an error, that error is
2205 /// returned. If the outer @ref result contains an ok value, and the inner
2206 /// @ref result contains an error, that inner error is returned.
2207 /// If the outer @ref result contains an ok value and the inner @ref result
2208 /// contains an ok value, that inner ok value is returned.
2209 ///
2210 /// If the outer @ref result and the inner @ref result have different error
2211 /// types, the returned @ref result will be one of these two types based on
2212 /// the following priority rules:
2213 ///
2214 /// 1. If the outer error type is `void`, use the inner error type
2215 /// 2. Else, if the inner error type is `void`, use the outer error type
2216 /// 3. Else, if the outer error type is constructible from the inner error
2217 /// type, use the outer error type.
2218 /// 4. Else, if the inner error type is constructible from the outer error
2219 /// type, use the inner error type.
2220 ///
2221 /// Note that only one level of @ref result is removed. For example, a
2222 /// `result<result<result<T, E>, E>, E>` will flatten to a
2223 /// `result<result<T, E>, E>`.
2224 ///
2225 /// ## Example
2226 /// ```
2227 /// result<result<int, const char*>, std::string> res1{in_place, 42};
2228 /// result<result<int, const char*>, std::string> res2{
2229 /// in_place, in_place_error, "oh no"};
2230 /// result<result<int, const char*>, std::string> res3{
2231 /// in_place_error, "oh no"};
2232 ///
2233 /// result<int, std::string> res1_flat = std::move(res1).flatten();
2234 /// result<int, std::string> res2_flat = std::move(res2).flatten();
2235 /// result<int, std::string> res3_flat = std::move(res3).flatten();
2236 ///
2237 /// assert(res1_flat.is_ok());
2238 /// assert(*res1_flat == 42);
2239 ///
2240 /// assert(res2_flat.is_error());
2241 /// assert(res2_flat.error() == "oh no");
2242 ///
2243 /// assert(res3_flat.is_error());
2244 /// assert(res3_flat.error() == "oh no");
2245 /// ```
2246 [[nodiscard]] constexpr auto flatten() &&
2247 #ifndef DOXYGEN
2248 requires(detail::is_result_v<T>)
2249 #endif
2250 {
2251 if constexpr (std::is_void_v<typename T::error_type>) {
2252 using ret_t = result<typename T::value_type, E>;
2253 if (is_ok()) {
2254 return ret_t{std::move(res_()[index<0>])};
2255 } else {
2256 if constexpr (std::is_void_v<E>) {
2257 return ret_t{in_place_error};
2258 } else {
2259 return ret_t{in_place_error, std::move(error())};
2260 }
2261 }
2262 } else if constexpr (std::is_void_v<E>) {
2263 using ret_t = T;
2264 if (is_ok()) {
2265 return std::move(res_()[index<0>]);
2266 } else {
2267 return ret_t{in_place_error, std::move(error())};
2268 }
2269 } else if constexpr (detail::traits<E>::template is_constructible<
2270 typename T::error_rvalue_reference>) {
2271 using ret_t = result<typename T::value_type, E>;
2272 if (is_ok()) {
2273 return ret_t{std::move(res_()[index<0>])};
2274 } else {
2275 return ret_t{in_place_error, std::move(error())};
2276 }
2277 } else if constexpr (detail::traits<typename T::error_type>::
2278 template is_constructible<error_rvalue_reference>) {
2279 using ret_t = T;
2280 if (is_ok()) {
2281 return std::move(res_()[index<0>]);
2282 } else {
2283 return ret_t{in_place_error, std::move(error())};
2284 }
2285 }
2286 }
2287
2288 /// @brief Converts nested @ref result types into a single @ref result
2289 ///
2290 /// @details
2291 /// Like @ref flatten, this function removes nested layers of @ref result,
2292 /// such as converting `result<result<T, E>, E>` into `result<T, E>`.
2293 /// However, unlike @ref flatten, this function removes all layers of
2294 /// nesting and works for unnested @ref result types. For example,
2295 /// `result<result<result<T, E>, E, E>` is converted directly to
2296 /// `result<T, E>`, and for `result<T, E>`, where `T` is not a @ref result
2297 /// type, no layers of @ref result are removed.
2298 ///
2299 /// ## Example
2300 /// ```
2301 /// using nested_result_t =
2302 /// result<result<result<int, std::string>, std::string, std::string>;
2303 ///
2304 /// nested_result_t res1{in_place, in_place, in_place, 42};
2305 /// nested_result_t res2{in_place_error, "oh no"};
2306 /// nested_result_t res3{in_place, in_place_error, "oh no"};
2307 /// nested_result_t res4{in_place, in_place, in_place_error, "oh no"};
2308 ///
2309 /// result<int, std::string> res1_flat = res1.flatten_all();
2310 /// result<int, std::string> res2_flat = res2.flatten_all();
2311 /// result<int, std::string> res3_flat = res3.flatten_all();
2312 /// result<int, std::string> res4_flat = res4.flatten_all();
2313 ///
2314 /// assert(res1_flat.is_ok());
2315 /// assert(*res1_flat == 42);
2316 ///
2317 /// assert(res2_flat.is_error());
2318 /// assert(res2_flat.error() == "oh no");
2319 ///
2320 /// assert(res3_flat.is_error());
2321 /// assert(res3_flat.error() == "oh no");
2322 ///
2323 /// assert(res3_flat.is_error());
2324 /// assert(res3_flat.error() == "oh no");
2325 /// ```
2326 [[nodiscard]] constexpr auto flatten_all() const& {
2327 if constexpr (detail::is_result_v<T>) {
2328 return flatten().flatten_all();
2329 } else {
2330 return *this;
2331 }
2332 }
2333
2334 /// @brief Converts nested @ref result types into a single @ref result
2335 ///
2336 /// @details
2337 /// Like @ref flatten, this function removes nested layers of @ref result,
2338 /// such as converting `result<result<T, E>, E>` into `result<T, E>`.
2339 /// However, unlike @ref flatten, this function removes all layers of
2340 /// nesting and works for unnested @ref result types. For example,
2341 /// `result<result<result<T, E>, E, E>` is converted directly to
2342 /// `result<T, E>`, and for `result<T, E>`, where `T` is not a @ref result
2343 /// type, no layers of @ref result are removed.
2344 ///
2345 /// ## Example
2346 /// ```
2347 /// using nested_result_t =
2348 /// result<result<result<int, std::string>, std::string, std::string>;
2349 ///
2350 /// nested_result_t res1{in_place, in_place, in_place, 42};
2351 /// nested_result_t res2{in_place_error, "oh no"};
2352 /// nested_result_t res3{in_place, in_place_error, "oh no"};
2353 /// nested_result_t res4{in_place, in_place, in_place_error, "oh no"};
2354 ///
2355 /// result<int, std::string> res1_flat = std::move(res1).flatten_all();
2356 /// result<int, std::string> res2_flat = std::move(res2).flatten_all();
2357 /// result<int, std::string> res3_flat = std::move(res3).flatten_all();
2358 /// result<int, std::string> res4_flat = std::move(res4).flatten_all();
2359 ///
2360 /// assert(res1_flat.is_ok());
2361 /// assert(*res1_flat == 42);
2362 ///
2363 /// assert(res2_flat.is_error());
2364 /// assert(res2_flat.error() == "oh no");
2365 ///
2366 /// assert(res3_flat.is_error());
2367 /// assert(res3_flat.error() == "oh no");
2368 ///
2369 /// assert(res3_flat.is_error());
2370 /// assert(res3_flat.error() == "oh no");
2371 /// ```
2372 [[nodiscard]] constexpr auto flatten_all() && {
2373 if constexpr (detail::is_result_v<T>) {
2374 return std::move(*this).flatten().flatten_all();
2375 } else {
2376 return std::move(*this);
2377 }
2378 }
2379
2380 /// @brief Converts `result<option<T>, E>` into `option<result<T, E>>`
2381 ///
2382 /// @details
2383 /// If the @ref result contains an error, the return value will be a @ref
2384 /// option that contains a @ref result that contains an error. If the @ref
2385 /// result contains an @ref option that contains a value, the return value
2386 /// will be a @ref option that contains @ref result that contains an ok
2387 /// value. If the @ref result contains a @ref option that is `none`, the
2388 /// return value will be an @ref option that is `none`.
2389 ///
2390 /// This function only participates in overload resolution of `T` is an
2391 /// @ref option.
2392 ///
2393 /// ## Example
2394 /// ```
2395 /// result<option<int>, std::string> val1{42};
2396 /// result<option<int>, std::string> val2{none};
2397 /// result<option<int>, std::string> val3{in_place_error, "oh no"};
2398 ///
2399 /// auto val1_trans = val1.transpose();
2400 /// auto val2_trans = val2.transpose();
2401 /// auto val3_trans = val3.transpose();
2402 ///
2403 /// assert(val1_trans.is_some());
2404 /// assert(val1_trans->is_ok());
2405 /// assert(**val1_trans == 42);
2406 ///
2407 /// assert(val2_trans.is_none());
2408 ///
2409 /// assert(val3_trans.is_some());
2410 /// assert(val3_trans->is_error());
2411 /// assert(val3_trans->error() == "oh no");
2412 /// ```
2413 [[nodiscard]] constexpr auto transpose() const&
2414 #ifndef DOXYGEN
2415 requires(detail::is_option_v<T>)
2416 #endif
2417 {
2418 using ret_t = option<result<typename T::value_type, E>>;
2419 if (is_ok()) {
2420 if (res_()[index<0>].is_some()) {
2421 return ret_t{in_place, in_place, *res_()[index<0>]};
2422 } else {
2423 return ret_t{none};
2424 }
2425 } else {
2426 return ret_t{in_place, in_place_error, error()};
2427 }
2428 }
2429
2430 /// @brief Converts `result<option<T>, E>` into `option<result<T, E>>`
2431 ///
2432 /// @details
2433 /// If the @ref result contains an error, the return value will be a @ref
2434 /// option that contains a @ref result that contains an error. If the @ref
2435 /// result contains an @ref option that contains a value, the return value
2436 /// will be a @ref option that contains @ref result that contains an ok
2437 /// value. If the @ref result contains a @ref option that is `none`, the
2438 /// return value will be an @ref option that is `none`.
2439 ///
2440 /// This function only participates in overload resolution of `T` is an
2441 /// @ref option.
2442 ///
2443 /// ## Example
2444 /// ```
2445 /// result<option<int>, std::string> val1{42};
2446 /// result<option<int>, std::string> val2{none};
2447 /// result<option<int>, std::string> val3{in_place_error, "oh no"};
2448 ///
2449 /// auto val1_trans = std::move(val1).transpose();
2450 /// auto val2_trans = std::move(val2).transpose();
2451 /// auto val3_trans = std::move(val3).transpose();
2452 ///
2453 /// assert(val1_trans.is_some());
2454 /// assert(val1_trans->is_ok());
2455 /// assert(**val1_trans == 42);
2456 ///
2457 /// assert(val2_trans.is_none());
2458 ///
2459 /// assert(val3_trans.is_some());
2460 /// assert(val3_trans->is_error());
2461 /// assert(val3_trans->error() == "oh no");
2462 /// ```
2463 [[nodiscard]] constexpr auto transpose() &&
2464 #ifndef DOXYGEN
2465 requires(detail::is_option_v<T>)
2466 #endif
2467 {
2468 using ret_t = option<result<typename T::value_type, E>>;
2469 if (is_ok()) {
2470 if (res_()[index<0>].is_some()) {
2471 return ret_t{in_place, in_place, std::move(*res_()[index<0>])};
2472 } else {
2473 return ret_t{none};
2474 }
2475 } else {
2476 return ret_t{in_place, in_place_error, std::move(error())};
2477 }
2478 }
2479
2480 /// @brief Swaps the ok and error types of a @ref result
2481 ///
2482 /// @details
2483 /// If the @ref result contains an ok value, a copy of the ok value will be
2484 /// returned as an error. If the @ref result contains an error value, the
2485 /// error value will be returned as an ok value.
2486 ///
2487 /// ## Example
2488 /// ```
2489 /// result<int, std::string> res1{42};
2490 /// result<int, std::string> res2{in_place_error, "oh no"};
2491 ///
2492 /// result<std::string, int> res1_inv = res1.invert();
2493 /// result<std::string, int> res2_inv = res2.invert();
2494 ///
2495 /// assert(res1_inv.is_error());
2496 /// assert(res1_inv.error() == 42);
2497 ///
2498 /// assert(res2_inv.is_ok());
2499 /// assert(*res2_inv == "oh no");
2500 /// ```
2501 [[nodiscard]] constexpr result<E, T> invert() const& {
2502 if (is_ok()) {
2503 return result<E, T>{in_place_error, res_()[0]};
2504 } else {
2505 return result<E, T>{in_place, error()};
2506 }
2507 }
2508
2509 /// @brief Swaps the ok and error types of a @ref result
2510 ///
2511 /// @details
2512 /// If the @ref result contains an ok value, a copy of the ok value will be
2513 /// returned as an error. If the @ref result contains an error value, the
2514 /// error value will be returned as an ok value.
2515 ///
2516 /// ## Example
2517 /// ```
2518 /// result<int, std::string> res1{42};
2519 /// result<int, std::string> res2{in_place_error, "oh no"};
2520 ///
2521 /// result<std::string, int> res1_inv = std::move(res1).invert();
2522 /// result<std::string, int> res2_inv = std::move(res2).invert();
2523 ///
2524 /// assert(res1_inv.is_error());
2525 /// assert(res1_inv.error() == 42);
2526 ///
2527 /// assert(res2_inv.is_ok());
2528 /// assert(*res2_inv == "oh no");
2529 /// ```
2530 [[nodiscard]] constexpr result<E, T> invert() && {
2531 if (is_ok()) {
2532 return result<E, T>{in_place_error, std::move(res_()[0])};
2533 } else {
2534 return result<E, T>{in_place, std::move(error())};
2535 }
2536 }
2537
2538 /// @brief Perforams a transformation on the error value of a @ref result
2539 ///
2540 /// @details
2541 /// If the @ref result contains an error value, that value is passed to the
2542 /// transformation callable provided. The value returned from the callable
2543 /// is then returned from this function as the error value of a new @ref
2544 /// result, where the error type of the new result is the exact type
2545 /// returned from the callable. If the @ref result contains an ok value, a
2546 /// copy of the ok value is returned.
2547 ///
2548 /// Note that this function is identical to @ref map_error, but the name
2549 /// `transform_error` makes @ref result able to be a drop in replacement
2550 /// for `std::expected`. `map_error` would be the more typical name of
2551 /// this monadic operation outside of C++.
2552 ///
2553 /// ## Example
2554 /// ```
2555 /// result<void, int> res1{};
2556 /// result<void, int> res2{in_place_error, 42};
2557 ///
2558 /// auto res1_mapped = res1.transform_error([](auto value) {
2559 /// return std::to_string(value);
2560 /// });
2561 /// auto res2_mapped = res2.transform_error([](auto value) {
2562 /// return std::to_string(value);
2563 /// });
2564 ///
2565 /// assert(res1_mapped.is_ok());
2566 ///
2567 /// assert(res2_mapped.is_error());
2568 /// assert(*res2_mapped == "42");
2569 /// ```
2570 template <typename F>
2571 constexpr auto transform_error(F&& f) & {
2572 if constexpr (std::is_void_v<E>) {
2573 using res_t = std::invoke_result_t<F, void_t>;
2574 if (res_().index() != 0) {
2575 if constexpr (std::is_void_v<res_t>) {
2576 std::invoke(std::forward<F>(f), void_v);
2577 return result<T, res_t>{in_place_error};
2578 } else {
2579 return result<T, res_t>{in_place_error,
2580 std::invoke(std::forward<F>(f), void_v)};
2581 }
2582 } else {
2583 if constexpr (std::is_void_v<T>) {
2584 return result<T, res_t>{std::in_place};
2585 } else {
2586 return result<T, res_t>{std::in_place, res_()[index<0>]};
2587 }
2588 }
2589 } else {
2590 using res_t = std::invoke_result_t<F, error_reference>;
2591 if (res_().index() != 0) {
2592 if constexpr (std::is_void_v<res_t>) {
2593 std::invoke(std::forward<F>(f), res_()[index<1>]);
2594 return result<T, res_t>{in_place_error};
2595 } else {
2596 return result<T, res_t>{
2597 in_place_error, std::invoke(std::forward<F>(f), res_()[index<1>])};
2598 }
2599 } else {
2600 if constexpr (std::is_void_v<T>) {
2601 return result<T, res_t>{std::in_place};
2602 } else {
2603 return result<T, res_t>{std::in_place, res_()[index<0>]};
2604 }
2605 }
2606 }
2607 }
2608
2609 /// @brief Perforams a transformation on the error value of a @ref result
2610 ///
2611 /// @details
2612 /// If the @ref result contains an error value, that value is passed to the
2613 /// transformation callable provided. The value returned from the callable
2614 /// is then returned from this function as the error value of a new @ref
2615 /// result, where the error type of the new result is the exact type
2616 /// returned from the callable. If the @ref result contains an ok value, a
2617 /// copy of the ok value is returned.
2618 ///
2619 /// Note that this function is identical to @ref map_error, but the name
2620 /// `transform_error` makes @ref result able to be a drop in replacement
2621 /// for `std::expected`. `map_error` would be the more typical name of
2622 /// this monadic operation outside of C++.
2623 ///
2624 /// ## Example
2625 /// ```
2626 /// const result<void, int> res1{};
2627 /// const result<void, int> res2{in_place_error, 42};
2628 ///
2629 /// auto res1_mapped = res1.transform_error([](auto value) {
2630 /// return std::to_string(value);
2631 /// });
2632 /// auto res2_mapped = res2.transform_error([](auto value) {
2633 /// return std::to_string(value);
2634 /// });
2635 ///
2636 /// assert(res1_mapped.is_ok());
2637 ///
2638 /// assert(res2_mapped.is_error());
2639 /// assert(*res2_mapped == "42");
2640 /// ```
2641 template <typename F>
2642 8 constexpr auto transform_error(F&& f) const& {
2643 if constexpr (std::is_void_v<E>) {
2644 using res_t = std::invoke_result_t<F, void_t>;
2645
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 2 times.
6 if (res_().index() != 0) {
2646 if constexpr (std::is_void_v<res_t>) {
2647 std::invoke(std::forward<F>(f), void_v);
2648 return result<T, res_t>{in_place_error};
2649 } else {
2650 return result<T, res_t>{in_place_error,
2651
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
4 std::invoke(std::forward<F>(f), void_v)};
2652 }
2653 } else {
2654 if constexpr (std::is_void_v<T>) {
2655 2 return result<T, res_t>{std::in_place};
2656 } else {
2657 2 return result<T, res_t>{std::in_place, res_()[index<0>]};
2658 }
2659 }
2660 } else {
2661 using res_t = std::invoke_result_t<F, error_const_reference>;
2662
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
2 if (res_().index() != 0) {
2663 if constexpr (std::is_void_v<res_t>) {
2664 std::invoke(std::forward<F>(f), res_()[index<1>]);
2665 return result<T, res_t>{in_place_error};
2666 } else {
2667 return result<T, res_t>{
2668
1/2
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
4 in_place_error, std::invoke(std::forward<F>(f), res_()[index<1>])};
2669 }
2670 } else {
2671 if constexpr (std::is_void_v<T>) {
2672 return result<T, res_t>{std::in_place};
2673 } else {
2674 return result<T, res_t>{std::in_place, res_()[index<0>]};
2675 }
2676 }
2677 }
2678 }
2679
2680 /// @brief Perforams a transformation on the error value of a @ref result
2681 ///
2682 /// @details
2683 /// If the @ref result contains an error value, that value is passed to the
2684 /// transformation callable provided. The value returned from the callable
2685 /// is then returned from this function as the error value of a new @ref
2686 /// result, where the error type of the new result is the exact type
2687 /// returned from the callable. If the @ref result contains an ok value,
2688 /// the ok value is returned.
2689 ///
2690 /// Note that this function is identical to @ref map_error, but the name
2691 /// `transform_error` makes @ref result able to be a drop in replacement
2692 /// for `std::expected`. `map_error` would be the more typical name of
2693 /// this monadic operation outside of C++.
2694 ///
2695 /// ## Example
2696 /// ```
2697 /// result<void, int> res1{};
2698 /// result<void, int> res2{in_place_error, 42};
2699 ///
2700 /// auto res1_mapped = std::move(res1).transform_error([](auto value) {
2701 /// return std::to_string(value);
2702 /// });
2703 /// auto res2_mapped = std::move(res2).transform_error([](auto value) {
2704 /// return std::to_string(value);
2705 /// });
2706 ///
2707 /// assert(res1_mapped.is_ok());
2708 ///
2709 /// assert(res2_mapped.is_error());
2710 /// assert(*res2_mapped == "42");
2711 /// ```
2712 template <typename F>
2713 constexpr auto transform_error(F&& f) && {
2714 if constexpr (std::is_void_v<E>) {
2715 using res_t = std::invoke_result_t<F, void_t>;
2716 if (res_().index() != 0) {
2717 if constexpr (std::is_void_v<res_t>) {
2718 std::invoke(std::forward<F>(f), void_v);
2719 return result<T, res_t>{in_place_error};
2720 } else {
2721 return result<T, res_t>{in_place_error,
2722 std::invoke(std::forward<F>(f), void_v)};
2723 }
2724 } else {
2725 if constexpr (std::is_void_v<T>) {
2726 return result<T, res_t>{std::in_place};
2727 } else {
2728 return result<T, res_t>{std::in_place,
2729 std::move(*this).res_()[index<0>]};
2730 }
2731 }
2732 } else {
2733 using res_t = std::invoke_result_t<F, error_rvalue_reference>;
2734 if (res_().index() != 0) {
2735 if constexpr (std::is_void_v<res_t>) {
2736 std::invoke(std::forward<F>(f), std::move(*this).res_()[index<1>]);
2737 return result<T, res_t>{in_place_error};
2738 } else {
2739 return result<T, res_t>{
2740 in_place_error,
2741 std::invoke(std::forward<F>(f), std::move(*this).res_()[index<1>])};
2742 }
2743 } else {
2744 if constexpr (std::is_void_v<T>) {
2745 return result<T, res_t>{std::in_place};
2746 } else {
2747 return result<T, res_t>{std::in_place,
2748 std::move(*this).res_()[index<0>]};
2749 }
2750 }
2751 }
2752 }
2753
2754 /// @brief Perforams a transformation on the error value of a @ref result
2755 ///
2756 /// @details
2757 /// If the @ref result contains an error value, that value is passed to the
2758 /// transformation callable provided. The value returned from the callable
2759 /// is then returned from this function as the error value of a new @ref
2760 /// result, where the error type of the new result is the exact type
2761 /// returned from the callable. If the @ref result contains an ok value,
2762 /// the ok value is returned.
2763 ///
2764 /// Note that this function is identical to @ref map_error, but the name
2765 /// `transform_error` makes @ref result able to be a drop in replacement
2766 /// for `std::expected`. `map_error` would be the more typical name of
2767 /// this monadic operation outside of C++.
2768 ///
2769 /// ## Example
2770 /// ```
2771 /// const result<void, int> res1{};
2772 /// const result<void, int> res2{in_place_error, 42};
2773 ///
2774 /// auto res1_mapped = std::move(res1).transform_error([](auto value) {
2775 /// return std::to_string(value);
2776 /// });
2777 /// auto res2_mapped = std::move(res2).transform_error([](auto value) {
2778 /// return std::to_string(value);
2779 /// });
2780 ///
2781 /// assert(res1_mapped.is_ok());
2782 ///
2783 /// assert(res2_mapped.is_error());
2784 /// assert(*res2_mapped == "42");
2785 /// ```
2786 template <typename F>
2787 constexpr auto transform_error(F&& f) const&& {
2788 if constexpr (std::is_void_v<E>) {
2789 using res_t = std::invoke_result_t<F, void_t>;
2790 if (res_().index() != 0) {
2791 if constexpr (std::is_void_v<res_t>) {
2792 std::invoke(std::forward<F>(f));
2793 return result<T, res_t>{in_place_error};
2794 } else {
2795 return result<T, res_t>{in_place_error,
2796 std::invoke(std::forward<F>(f), void_v)};
2797 }
2798 } else {
2799 if constexpr (std::is_void_v<T>) {
2800 return result<T, res_t>{std::in_place};
2801 } else {
2802 return result<T, res_t>{std::in_place,
2803 std::move(*this).res_()[index<0>]};
2804 }
2805 }
2806 } else {
2807 using res_t = std::invoke_result_t<F, error_const_rvalue_reference>;
2808 if (res_().index() != 0) {
2809 if constexpr (std::is_void_v<res_t>) {
2810 std::invoke(std::forward<F>(f), std::move(*this).res_()[index<1>]);
2811 return result<T, res_t>{in_place_error};
2812 } else {
2813 return result<T, res_t>{
2814 in_place_error,
2815 std::invoke(std::forward<F>(f), std::move(*this).res_()[index<1>])};
2816 }
2817 } else {
2818 if constexpr (std::is_void_v<T>) {
2819 return result<T, res_t>{std::in_place};
2820 } else {
2821 return result<T, res_t>{std::in_place,
2822 std::move(*this).res_()[index<0>]};
2823 }
2824 }
2825 }
2826 }
2827
2828 /// @brief Perforams a transformation on the error value of a @ref result
2829 ///
2830 /// @details
2831 /// If the @ref result contains an error value, that value is passed to the
2832 /// transformation callable provided. The value returned from the callable
2833 /// is then returned from this function as the error value of a new @ref
2834 /// result, where the error type of the new result is the exact type
2835 /// returned from the callable. If the @ref result contains an ok value, a
2836 /// copy of the ok value is returned.
2837 ///
2838 /// Note that this function is identical to @ref transform_error, but the
2839 /// name `map_error` is more typical for this sort of monadic operation
2840 /// outside of C++.
2841 ///
2842 /// ## Example
2843 /// ```
2844 /// result<void, int> res1{};
2845 /// result<void, int> res2{in_place_error, 42};
2846 ///
2847 /// auto res1_mapped = res1.map_error([](auto value) {
2848 /// return std::to_string(value);
2849 /// });
2850 /// auto res2_mapped = res2.map_error([](auto value) {
2851 /// return std::to_string(value);
2852 /// });
2853 ///
2854 /// assert(res1_mapped.is_ok());
2855 ///
2856 /// assert(res2_mapped.is_error());
2857 /// assert(*res2_mapped == "42");
2858 /// ```
2859 template <typename F>
2860 constexpr auto map_error(F&& f) & {
2861 return transform_error(std::forward<F>(f));
2862 }
2863
2864 /// @brief Perforams a transformation on the error value of a @ref result
2865 ///
2866 /// @details
2867 /// If the @ref result contains an error value, that value is passed to the
2868 /// transformation callable provided. The value returned from the callable
2869 /// is then returned from this function as the error value of a new @ref
2870 /// result, where the error type of the new result is the exact type
2871 /// returned from the callable. If the @ref result contains an ok value, a
2872 /// copy of the ok value is returned.
2873 ///
2874 /// Note that this function is identical to @ref transform_error, but the
2875 /// name `map_error` is more typical for this sort of monadic operation
2876 /// outside of C++.
2877 ///
2878 /// ## Example
2879 /// ```
2880 /// const result<void, int> res1{};
2881 /// const result<void, int> res2{in_place_error, 42};
2882 ///
2883 /// auto res1_mapped = res1.map_error([](auto value) {
2884 /// return std::to_string(value);
2885 /// });
2886 /// auto res2_mapped = res2.map_error([](auto value) {
2887 /// return std::to_string(value);
2888 /// });
2889 ///
2890 /// assert(res1_mapped.is_ok());
2891 ///
2892 /// assert(res2_mapped.is_error());
2893 /// assert(*res2_mapped == "42");
2894 /// ```
2895 template <typename F>
2896 constexpr auto map_error(F&& f) const& {
2897 return transform_error(std::forward<F>(f));
2898 }
2899
2900 /// @brief Perforams a transformation on the error value of a @ref result
2901 ///
2902 /// @details
2903 /// If the @ref result contains an error value, that value is passed to the
2904 /// transformation callable provided. The value returned from the callable
2905 /// is then returned from this function as the error value of a new @ref
2906 /// result, where the error type of the new result is the exact type
2907 /// returned from the callable. If the @ref result contains an ok value,
2908 /// the ok value is returned.
2909 ///
2910 /// Note that this function is identical to @ref transform_error, but the
2911 /// name `map_error` is more typical for this sort of monadic operation
2912 /// outside of C++.
2913 ///
2914 /// ## Example
2915 /// ```
2916 /// result<void, int> res1{};
2917 /// result<void, int> res2{in_place_error, 42};
2918 ///
2919 /// auto res1_mapped = std::move(res1).map_error([](auto value) {
2920 /// return std::to_string(value);
2921 /// });
2922 /// auto res2_mapped = std::move(res2).map_error([](auto value) {
2923 /// return std::to_string(value);
2924 /// });
2925 ///
2926 /// assert(res1_mapped.is_ok());
2927 ///
2928 /// assert(res2_mapped.is_error());
2929 /// assert(*res2_mapped == "42");
2930 /// ```
2931 template <typename F>
2932 constexpr auto map_error(F&& f) && {
2933 return std::move(*this).transform_error(std::forward<F>(f));
2934 }
2935
2936 /// @brief Perforams a transformation on the error value of a @ref result
2937 ///
2938 /// @details
2939 /// If the @ref result contains an error value, that value is passed to the
2940 /// transformation callable provided. The value returned from the callable
2941 /// is then returned from this function as the error value of a new @ref
2942 /// result, where the error type of the new result is the exact type
2943 /// returned from the callable. If the @ref result contains an ok value,
2944 /// the ok value is returned.
2945 ///
2946 /// Note that this function is identical to @ref transform_error, but the
2947 /// name `map_error` is more typical for this sort of monadic operation
2948 /// outside of C++.
2949 ///
2950 /// ## Example
2951 /// ```
2952 /// result<void, int> res1{};
2953 /// result<void, int> res2{in_place_error, 42};
2954 ///
2955 /// auto res1_mapped = std::move(res1).map_error([](auto value) {
2956 /// return std::to_string(value);
2957 /// });
2958 /// auto res2_mapped = std::move(res2).map_error([](auto value) {
2959 /// return std::to_string(value);
2960 /// });
2961 ///
2962 /// assert(res1_mapped.is_ok());
2963 ///
2964 /// assert(res2_mapped.is_error());
2965 /// assert(*res2_mapped == "42");
2966 /// ```
2967 template <typename F>
2968 constexpr auto map_error(F&& f) const&& {
2969 return std::move(*this).transform_error(std::forward<F>(f));
2970 }
2971
2972 /// @brief Converts a @ref result reference into a @ref result of references
2973 ///
2974 /// @details
2975 /// ## Example
2976 /// ```
2977 /// result<int, std::string> res1{42};
2978 /// result<int, std::string> res2{in_place_error, "oh no"};
2979 ///
2980 /// result<int&, std::string&> res1_ref = res1.ref();
2981 /// result<int&, std::string&> ref2_ref = res2.ref();
2982 ///
2983 /// assert(res1_ref.is_ok());
2984 /// assert(&*res1_ref == &*res1);
2985 ///
2986 /// assert(res2_ref.is_error());
2987 /// assert(&res2_ref.error() == &res2.error());
2988 /// ```
2989 [[nodiscard]] constexpr result<reference, error_reference> ref() noexcept {
2990 if (res_().index() == 0) {
2991 if constexpr (std::is_void_v<T>) {
2992 return result<reference, error_reference>{std::in_place};
2993 } else {
2994 return result<reference, error_reference>{std::in_place, **this};
2995 }
2996 } else {
2997 if constexpr (std::is_void_v<E>) {
2998 return result<reference, error_reference>{in_place_error};
2999 } else {
3000 return result<reference, error_reference>{in_place_error, error()};
3001 }
3002 }
3003 }
3004
3005 /// @brief Converts a @ref result reference into a @ref result of references
3006 ///
3007 /// @details
3008 /// ## Example
3009 /// ```
3010 /// const result<int, std::string> res1{42};
3011 /// const result<int, std::string> res2{in_place_error, "oh no"};
3012 ///
3013 /// result<const int&, const std::string&> res1_ref = res1.ref();
3014 /// result<const int&, const std::string&> ref2_ref = res2.ref();
3015 ///
3016 /// assert(res1_ref.is_ok());
3017 /// assert(&*res1_ref == &*res1);
3018 ///
3019 /// assert(res2_ref.is_error());
3020 /// assert(&res2_ref.error() == &res2.error());
3021 /// ```
3022 2 [[nodiscard]] constexpr result<const_reference, error_const_reference> ref()
3023 const noexcept {
3024
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
2 if (res_().index() == 0) {
3025 if constexpr (std::is_void_v<T>) {
3026 return result<const_reference, error_const_reference>{std::in_place};
3027 } else {
3028 return result<const_reference, error_const_reference>{std::in_place,
3029 1 **this};
3030 }
3031 } else {
3032 if constexpr (std::is_void_v<E>) {
3033 return result<const_reference, error_const_reference>{in_place_error};
3034 } else {
3035 return result<const_reference, error_const_reference>{in_place_error,
3036 1 error()};
3037 }
3038 }
3039 }
3040
3041 /// @brief Converts a @ref result reference into a @ref result of references
3042 ///
3043 /// @details
3044 /// ## Example
3045 /// ```
3046 /// result<int, std::string> res1{42};
3047 /// result<int, std::string> res2{in_place_error, "oh no"};
3048 ///
3049 /// result<const int&, const std::string&> res1_ref = res1.cref();
3050 /// result<const int&, const std::string&> ref2_ref = res2.cref();
3051 ///
3052 /// assert(res1_ref.is_ok());
3053 /// assert(&*res1_ref == &*res1);
3054 ///
3055 /// assert(res2_ref.is_error());
3056 /// assert(&res2_ref.error() == &res2.error());
3057 /// ```
3058 [[nodiscard]] constexpr result<const_reference, error_const_reference> cref()
3059 const noexcept {
3060 return ref();
3061 }
3062
3063 /// @brief Discards error values and converts into an @ref option
3064 ///
3065 /// @details
3066 /// If the @ref result contains an ok value, a copy of that value is
3067 /// returned wrapped in an @ref option. If the @ref result contains an
3068 /// error, `none` is returned.
3069 ///
3070 /// ## Example
3071 /// ```
3072 /// result<int, std::string> res1{42};
3073 /// result<int, std::string> res2{in_place_error, "oh no"};
3074 ///
3075 /// option<int> opt1 = res1.or_none();
3076 /// option<int> opt2 = res2.or_none();
3077 ///
3078 /// assert(opt1.is_some());
3079 /// assert(*opt1 == 42);
3080 ///
3081 /// assert(opt2.is_none());
3082 /// ```
3083 8 [[nodiscard]] constexpr option<T> or_none() const& noexcept {
3084
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
8 if (res_().index() == 0) {
3085 if constexpr (std::is_void_v<T>) {
3086 2 return option<T>{std::in_place};
3087 } else {
3088 2 return option<T>{std::in_place, res_()[index<0>]};
3089 }
3090 } else {
3091 4 return option<T>{};
3092 }
3093 }
3094
3095 /// @brief Discards error values and converts into an @ref option
3096 ///
3097 /// @details
3098 /// If the @ref result contains an ok value, that value is
3099 /// returned wrapped in an @ref option. If the @ref result contains an
3100 /// error, `none` is returned.
3101 ///
3102 /// ## Example
3103 /// ```
3104 /// result<int, std::string> res1{42};
3105 /// result<int, std::string> res2{in_place_error, "oh no"};
3106 ///
3107 /// option<int> opt1 = std::move(res1).or_none();
3108 /// option<int> opt2 = std::move(res2).or_none();
3109 ///
3110 /// assert(opt1.is_some());
3111 /// assert(*opt1 == 42);
3112 ///
3113 /// assert(opt2.is_none());
3114 /// ```
3115 [[nodiscard]] constexpr option<T> or_none() && {
3116 if (res_().index() == 0) {
3117 if constexpr (std::is_void_v<T>) {
3118 return option<T>{std::in_place};
3119 } else {
3120 return option<T>{std::in_place, std::move(*this).res_()[index<0>]};
3121 }
3122 } else {
3123 return option<T>{};
3124 }
3125 }
3126
3127 /// @brief Discards error values and converts into an @ref option
3128 ///
3129 /// @details
3130 /// If the @ref result contains an ok value, a copy of that value is
3131 /// returned wrapped in an @ref option. If the @ref result contains an
3132 /// error, `none` is returned.
3133 ///
3134 /// ## Example
3135 /// ```
3136 /// result<int, std::string> res1{42};
3137 /// result<int, std::string> res2{in_place_error, "oh no"};
3138 ///
3139 /// option<int> opt1 = res1.ok_or_none();
3140 /// option<int> opt2 = res2.ok_or_none();
3141 ///
3142 /// assert(opt1.is_some());
3143 /// assert(*opt1 == 42);
3144 ///
3145 /// assert(opt2.is_none());
3146 /// ```
3147 [[nodiscard]] constexpr option<T> ok_or_none() const& noexcept { return or_none(); }
3148
3149 /// @brief Discards error values and converts into an @ref option
3150 ///
3151 /// @details
3152 /// If the @ref result contains an ok value, that value is
3153 /// returned wrapped in an @ref option. If the @ref result contains an
3154 /// error, `none` is returned.
3155 ///
3156 /// ## Example
3157 /// ```
3158 /// result<int, std::string> res1{42};
3159 /// result<int, std::string> res2{in_place_error, "oh no"};
3160 ///
3161 /// option<int> opt1 = std::move(res1).ok_or_none();
3162 /// option<int> opt2 = std::move(res2).ok_or_none();
3163 ///
3164 /// assert(opt1.is_some());
3165 /// assert(*opt1 == 42);
3166 ///
3167 /// assert(opt2.is_none());
3168 /// ```
3169 [[nodiscard]] constexpr option<T> ok_or_none() && { return std::move(*this).or_none(); }
3170
3171 /// @brief Discards ok value and converts into an @ref option
3172 ///
3173 /// @details
3174 /// If the @ref result contains an error value, a copy of that value is
3175 /// returned wrapped in an @ref option. If the @ref result contains an ok
3176 /// value, `none` is returned.
3177 ///
3178 /// ## Example
3179 /// ```
3180 /// result<int, std::string> res1{42};
3181 /// result<int, std::string> res2{in_place_error, "oh no"};
3182 ///
3183 /// option<std::string> opt1 = res1.error_or_none();
3184 /// option<std::string> opt2 = res2.error_or_none();
3185 ///
3186 /// assert(opt1.is_none());
3187 ///
3188 /// assert(opt2.is_some());
3189 /// assert(*opt2 == "oh no");
3190 /// ```
3191 8 [[nodiscard]] constexpr option<E> error_or_none() const& noexcept {
3192
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
8 if (res_().index() != 0) {
3193 if constexpr (std::is_void_v<E>) {
3194 2 return option<E>{std::in_place};
3195 } else {
3196 2 return option<E>{std::in_place, res_()[index<1>]};
3197 }
3198 } else {
3199 4 return option<E>{};
3200 }
3201 }
3202
3203 /// @brief Discards ok value and converts into an @ref option
3204 ///
3205 /// @details
3206 /// If the @ref result contains an error value, that value is
3207 /// returned wrapped in an @ref option. If the @ref result contains an ok
3208 /// value, `none` is returned.
3209 ///
3210 /// ## Example
3211 /// ```
3212 /// result<int, std::string> res1{42};
3213 /// result<int, std::string> res2{in_place_error, "oh no"};
3214 ///
3215 /// option<std::string> opt1 = res1.error_or_none();
3216 /// option<std::string> opt2 = res2.error_or_none();
3217 ///
3218 /// assert(opt1.is_none());
3219 ///
3220 /// assert(opt2.is_some());
3221 /// assert(*opt2 == "oh no");
3222 /// ```
3223 [[nodiscard]] constexpr option<E> error_or_none() && {
3224 if (res_().index() != 0) {
3225 if constexpr (std::is_void_v<E>) {
3226 return option<E>{std::in_place};
3227 } else {
3228 return option<E>{std::in_place, std::move(*this).res_()[index<1>]};
3229 }
3230 } else {
3231 return option<E>{};
3232 }
3233 }
3234
3235 /// @brief Constructs a new ok value in place into the @ref result
3236 ///
3237 /// @details
3238 /// The value previously contained in the @ref result, ok or error, is
3239 /// destroyed in place. The new ok value is then constructed in place
3240 /// as if by placement new.
3241 ///
3242 /// ## Example
3243 /// ```
3244 /// result<std::string, int> res1{in_place_error, 42};
3245 /// result<std::string, int> res2{""};
3246 ///
3247 /// res1.emplace(5, 'a');
3248 /// res2.emplace(5, 'a');
3249 ///
3250 /// assert(res1.is_ok());
3251 /// assert(*res1 == "aaaaa");
3252 ///
3253 /// assert(res2.is_ok());
3254 /// assert(*res2 == "aaaaa");
3255 /// ```
3256 template <typename... Args>
3257 constexpr reference emplace(Args&&... args) {
3258 return res_().template emplace<0>(std::forward<Args>(args)...);
3259 }
3260
3261 /// @brief Constructs a new ok value in place into the @ref result
3262 ///
3263 /// @details
3264 /// The value previously contained in the @ref result, ok or error, is
3265 /// destroyed in place. The new ok value is then constructed in place
3266 /// as if by placement new.
3267 ///
3268 /// ## Example
3269 /// ```
3270 /// result<std::vector<int>, int> res1{in_place_error, 42};
3271 /// result<std::vector<int>, int> res2{};
3272 ///
3273 /// res1.emplace({1, 2, 3, 4, 5});
3274 /// res2.emplace({1, 2, 3, 4, 5});
3275 ///
3276 /// assert(res1.is_ok());
3277 /// assert(res1->size() == 5);
3278 ///
3279 /// assert(res2.is_ok());
3280 /// assert(res2->size() == 5);
3281 /// ```
3282 template <typename U, typename... Args>
3283 constexpr reference emplace(std::initializer_list<U> ilist, Args&&... args) {
3284 return res_().template emplace<0>(ilist, std::forward<Args>(args)...);
3285 }
3286
3287 /// @brief Constructs a new error value in place into the @ref result
3288 ///
3289 /// @details
3290 /// The value previously contained in the @ref result, ok or error, is
3291 /// destroyed in place. The new error value is then constructed in place
3292 /// as if by placement new.
3293 ///
3294 /// ## Example
3295 /// ```
3296 /// result<int, std::string> res1{42};
3297 /// result<int, std::string> res2{in_place_error, ""};
3298 ///
3299 /// res1.emplace_error(5, 'a');
3300 /// res2.emplace_error(5, 'a');
3301 ///
3302 /// assert(res1.is_error());
3303 /// assert(res1.error() == "aaaaa");
3304 ///
3305 /// assert(res2.is_error());
3306 /// assert(res2.error() == "aaaaa");
3307 /// ```
3308 template <typename... Args>
3309 constexpr error_reference emplace_error(Args&&... args) {
3310 return res_().template emplace<1>(std::forward<Args>(args)...);
3311 }
3312
3313 /// @brief Constructs a new error value in place into the @ref result
3314 ///
3315 /// @details
3316 /// The value previously contained in the @ref result, ok or error, is
3317 /// destroyed in place. The new error value is then constructed in place
3318 /// as if by placement new.
3319 ///
3320 /// ## Example
3321 /// ```
3322 /// result<int, std::vector<int>> res1{42};
3323 /// result<int, std::vector<int>> res2{in_place_error};
3324 ///
3325 /// res1.emplace_error({1, 2, 3, 4, 5});
3326 /// res2.emplace_error({1, 2, 3, 4, 5});
3327 ///
3328 /// assert(res1.is_error());
3329 /// assert(res1.error().size() == 5);
3330 ///
3331 /// assert(res2.is_error());
3332 /// assert(res2.error().size() == 5);
3333 /// ```
3334 template <typename U, typename... Args>
3335 constexpr error_reference emplace_error(std::initializer_list<U> ilist,
3336 Args&&... args) {
3337 return res_().template emplace<1>(ilist, std::forward<Args>(args)...);
3338 }
3339
3340 /// @brief Invokes a visitor witht he contained value
3341 ///
3342 /// @details
3343 /// This function treats a @ref result as if it was a @ref variant of
3344 /// `T` and `E` (i.e. `variant<T, E>`). If the @ref result contians an ok
3345 /// value, that value is passed to the visitor. If the @ref result contains
3346 /// an error, the error is passed to the visitor. When either `T` or `E`
3347 /// are `void`, an instance of @ref void_t is passed instead.
3348 ///
3349 /// Note that the @ref overload function can be helpful for defining a
3350 /// visiotr inline.
3351 ///
3352 /// ## Example
3353 /// ```
3354 /// result<int, std::string> res1{42};
3355 /// result<int, std::string> res2{in_place_error, "oh no"};
3356 ///
3357 /// res1.visit(overload([](int ok_val) {
3358 /// assert(ok_val == 42);
3359 /// }, [](std::string& err_val) {
3360 /// assert(false);
3361 /// }));
3362 ///
3363 /// res2.visit(overload([](int ok_val) {
3364 /// assert(false);
3365 /// }, [](std::string& err_val) {
3366 /// assert(err_val == "oh no");
3367 /// }));
3368 /// ```
3369 template <typename V>
3370 constexpr
3371 #ifndef DOXYGEN
3372 decltype(auto)
3373 #else
3374 DEDUCED
3375 #endif
3376 visit(V&& visitor) & {
3377 return res_().visit(std::forward<V>(visitor));
3378 }
3379
3380 /// @brief Invokes a visitor witht he contained value
3381 ///
3382 /// @details
3383 /// This function treats a @ref result as if it was a @ref variant of
3384 /// `T` and `E` (i.e. `variant<T, E>`). If the @ref result contians an ok
3385 /// value, that value is passed to the visitor. If the @ref result contains
3386 /// an error, the error is passed to the visitor. When either `T` or `E`
3387 /// are `void`, an instance of @ref void_t is passed instead.
3388 ///
3389 /// Note that the @ref overload function can be helpful for defining a
3390 /// visiotr inline.
3391 ///
3392 /// ## Example
3393 /// ```
3394 /// const result<int, std::string> res1{42};
3395 /// const result<int, std::string> res2{in_place_error, "oh no"};
3396 ///
3397 /// res1.visit(overload([](int ok_val) {
3398 /// assert(ok_val == 42);
3399 /// }, [](const std::string& err_val) {
3400 /// assert(false);
3401 /// }));
3402 ///
3403 /// res2.visit(overload([](int ok_val) {
3404 /// assert(false);
3405 /// }, [](const std::string& err_val) {
3406 /// assert(err_val == "oh no");
3407 /// }));
3408 /// ```
3409 template <typename V>
3410 constexpr
3411 #ifndef DOXYGEN
3412 decltype(auto)
3413 #else
3414 DEDUCED
3415 #endif
3416 4 visit(V&& visitor) const& {
3417 4 return res_().visit(std::forward<V>(visitor));
3418 }
3419
3420 /// @brief Invokes a visitor witht he contained value
3421 ///
3422 /// @details
3423 /// This function treats a @ref result as if it was a @ref variant of
3424 /// `T` and `E` (i.e. `variant<T, E>`). If the @ref result contians an ok
3425 /// value, that value is passed to the visitor. If the @ref result contains
3426 /// an error, the error is passed to the visitor. When either `T` or `E`
3427 /// are `void`, an instance of @ref void_t is passed instead.
3428 ///
3429 /// Note that the @ref overload function can be helpful for defining a
3430 /// visiotr inline.
3431 ///
3432 /// ## Example
3433 /// ```
3434 /// result<int, std::string> res1{42};
3435 /// result<int, std::string> res2{in_place_error, "oh no"};
3436 ///
3437 /// std::move(res1).visit(overload([](int ok_val) {
3438 /// assert(ok_val == 42);
3439 /// }, [](std::string err_val) {
3440 /// assert(false);
3441 /// }));
3442 ///
3443 /// std::move(res2).visit(overload([](int ok_val) {
3444 /// assert(false);
3445 /// }, [](std::string err_val) {
3446 /// assert(err_val == "oh no");
3447 /// }));
3448 /// ```
3449 template <typename V>
3450 constexpr
3451 #ifndef DOXYGEN
3452 decltype(auto)
3453 #else
3454 DEDUCED
3455 #endif
3456 visit(V&& visitor) && {
3457 return std::move(*this).res_().visit(std::forward<V>(visitor));
3458 }
3459
3460 /// @brief Invokes a visitor witht he contained value
3461 ///
3462 /// @details
3463 /// This function treats a @ref result as if it was a @ref variant of
3464 /// `T` and `E` (i.e. `variant<T, E>`). If the @ref result contians an ok
3465 /// value, that value is passed to the visitor. If the @ref result contains
3466 /// an error, the error is passed to the visitor. When either `T` or `E`
3467 /// are `void`, an instance of @ref void_t is passed instead.
3468 ///
3469 /// Note that the @ref overload function can be helpful for defining a
3470 /// visiotr inline.
3471 ///
3472 /// ## Example
3473 /// ```
3474 /// const result<int, std::string> res1{42};
3475 /// const result<int, std::string> res2{in_place_error, "oh no"};
3476 ///
3477 /// std::move(res1).visit(overload([](int ok_val) {
3478 /// assert(ok_val == 42);
3479 /// }, [](std::string err_val) {
3480 /// assert(false);
3481 /// }));
3482 ///
3483 /// std::move(res2).visit(overload([](int ok_val) {
3484 /// assert(false);
3485 /// }, [](std::string err_val) {
3486 /// assert(err_val == "oh no");
3487 /// }));
3488 /// ```
3489 template <typename V>
3490 constexpr
3491 #ifndef DOXYGEN
3492 decltype(auto)
3493 #else
3494 DEDUCED
3495 #endif
3496 visit(V&& visitor) const&& {
3497 return std::move(*this).res_().visit(std::forward<V>(visitor));
3498 }
3499
3500 /// @brief Invokes a visitor with the contained value and meta data
3501 ///
3502 /// @details
3503 /// This function treats a @ref result as if it was a @ref variant of
3504 /// `T` and `E` (i.e. `variant<T, E>`). If the @ref result contians an ok
3505 /// value, that value is passed to the visitor. If the @ref result contains
3506 /// an error, the error is passed to the visitor. When either `T` or `E`
3507 /// are `void`, an instance of @ref void_t is passed instead.
3508 ///
3509 /// Unlike @ref visit, this function also passes an extra meta data value
3510 /// when invoking the visitor. This meta data object provides `constexpr`
3511 /// information about the type and index of the value being visited. The ok
3512 /// value has index 0 and the error value has index 1. This object has the
3513 /// the API shown below.
3514 ///
3515 /// ```
3516 /// struct alternative_info {
3517 /// // index of the alternative (ok == 0, error == 1)
3518 /// static inline constexpr size_t index = ...;
3519 ///
3520 /// // type of the alternative (ok == T, error == E)
3521 /// using type = ...;
3522 ///
3523 /// // helper function for forwarding non-const alternative values
3524 /// // without needing to provide a template argument.
3525 /// static constexpr decltype(auto) forward(...);
3526 /// }
3527 /// ```
3528 ///
3529 /// Note that the @ref overload function can be helpful for defining a
3530 /// visitor inline.
3531 ///
3532 /// ## Example
3533 /// ```
3534 /// result<int, std::string> res1{42};
3535 /// result<int, std::string> res2{in_place_error, "oh no"};
3536 ///
3537 /// res1.visit_informed([](auto&& value, auto info) {
3538 /// if constexpr (info.index == 0) { // ok
3539 /// assert(value == 42);
3540 /// } else if constexpr (info.index == 1) { // error
3541 /// assert(false);
3542 /// }
3543 /// });
3544 ///
3545 /// res2.visit_informed([](auto&& value, auto info) {
3546 /// if constexpr (info.index == 0) { // ok
3547 /// assert(false);
3548 /// } else if constexpr (info.index == 1) { // error
3549 /// assert(value == "oh no");
3550 /// }
3551 /// });
3552 /// ```
3553 template <typename V>
3554 constexpr
3555 #ifndef DOXYGEN
3556 decltype(auto)
3557 #else
3558 DEDUCED
3559 #endif
3560 visit_informed(V&& visitor) & {
3561 return res_().visit_informed(std::forward<V>(visitor));
3562 }
3563
3564 /// @brief Invokes a visitor with the contained value and meta data
3565 ///
3566 /// @details
3567 /// This function treats a @ref result as if it was a @ref variant of
3568 /// `T` and `E` (i.e. `variant<T, E>`). If the @ref result contians an ok
3569 /// value, that value is passed to the visitor. If the @ref result contains
3570 /// an error, the error is passed to the visitor. When either `T` or `E`
3571 /// are `void`, an instance of @ref void_t is passed instead.
3572 ///
3573 /// Unlike @ref visit, this function also passes an extra meta data value
3574 /// when invoking the visitor. This meta data object provides `constexpr`
3575 /// information about the type and index of the value being visited. The ok
3576 /// value has index 0 and the error value has index 1. This object has the
3577 /// the API shown below.
3578 ///
3579 /// ```
3580 /// struct alternative_info {
3581 /// // index of the alternative (ok == 0, error == 1)
3582 /// static inline constexpr size_t index = ...;
3583 ///
3584 /// // type of the alternative (ok == T, error == E)
3585 /// using type = ...;
3586 ///
3587 /// // helper function for forwarding non-const alternative values
3588 /// // without needing to provide a template argument.
3589 /// static constexpr decltype(auto) forward(...);
3590 /// }
3591 /// ```
3592 ///
3593 /// Note that the @ref overload function can be helpful for defining a
3594 /// visitor inline.
3595 ///
3596 /// ## Example
3597 /// ```
3598 /// const result<int, std::string> res1{42};
3599 /// const result<int, std::string> res2{in_place_error, "oh no"};
3600 ///
3601 /// res1.visit_informed([](auto&& value, auto info) {
3602 /// if constexpr (info.index == 0) { // ok
3603 /// assert(value == 42);
3604 /// } else if constexpr (info.index == 1) { // error
3605 /// assert(false);
3606 /// }
3607 /// });
3608 ///
3609 /// res2.visit_informed([](auto&& value, auto info) {
3610 /// if constexpr (info.index == 0) { // ok
3611 /// assert(false);
3612 /// } else if constexpr (info.index == 1) { // error
3613 /// assert(value == "oh no");
3614 /// }
3615 /// });
3616 /// ```
3617 template <typename V>
3618 constexpr
3619 #ifndef DOXYGEN
3620 decltype(auto)
3621 #else
3622 DEDUCED
3623 #endif
3624 visit_informed(V&& visitor) const& {
3625 return res_().visit_informed(std::forward<V>(visitor));
3626 }
3627
3628 /// @brief Invokes a visitor with the contained value and meta data
3629 ///
3630 /// @details
3631 /// This function treats a @ref result as if it was a @ref variant of
3632 /// `T` and `E` (i.e. `variant<T, E>`). If the @ref result contians an ok
3633 /// value, that value is passed to the visitor. If the @ref result contains
3634 /// an error, the error is passed to the visitor. When either `T` or `E`
3635 /// are `void`, an instance of @ref void_t is passed instead.
3636 ///
3637 /// Unlike @ref visit, this function also passes an extra meta data value
3638 /// when invoking the visitor. This meta data object provides `constexpr`
3639 /// information about the type and index of the value being visited. The ok
3640 /// value has index 0 and the error value has index 1. This object has the
3641 /// the API shown below.
3642 ///
3643 /// ```
3644 /// struct alternative_info {
3645 /// // index of the alternative (ok == 0, error == 1)
3646 /// static inline constexpr size_t index = ...;
3647 ///
3648 /// // type of the alternative (ok == T, error == E)
3649 /// using type = ...;
3650 ///
3651 /// // helper function for forwarding non-const alternative values
3652 /// // without needing to provide a template argument.
3653 /// static constexpr decltype(auto) forward(...);
3654 /// }
3655 /// ```
3656 ///
3657 /// Note that the @ref overload function can be helpful for defining a
3658 /// visitor inline.
3659 ///
3660 /// ## Example
3661 /// ```
3662 /// result<int, std::string> res1{42};
3663 /// result<int, std::string> res2{in_place_error, "oh no"};
3664 ///
3665 /// std::move(res1).visit_informed([](auto&& value, auto info) {
3666 /// if constexpr (info.index == 0) { // ok
3667 /// assert(value == 42);
3668 /// } else if constexpr (info.index == 1) { // error
3669 /// assert(false);
3670 /// }
3671 /// });
3672 ///
3673 /// std::move(res2).visit_informed([](auto&& value, auto info) {
3674 /// if constexpr (info.index == 0) { // ok
3675 /// assert(false);
3676 /// } else if constexpr (info.index == 1) { // error
3677 /// assert(value == "oh no");
3678 /// }
3679 /// });
3680 /// ```
3681 template <typename V>
3682 constexpr
3683 #ifndef DOXYGEN
3684 decltype(auto)
3685 #else
3686 DEDUCED
3687 #endif
3688 visit_informed(V&& visitor) && {
3689 return std::move(*this).res_().visit_informed(std::forward<V>(visitor));
3690 }
3691
3692 /// @brief Invokes a visitor with the contained value and meta data
3693 ///
3694 /// @details
3695 /// This function treats a @ref result as if it was a @ref variant of
3696 /// `T` and `E` (i.e. `variant<T, E>`). If the @ref result contians an ok
3697 /// value, that value is passed to the visitor. If the @ref result contains
3698 /// an error, the error is passed to the visitor. When either `T` or `E`
3699 /// are `void`, an instance of @ref void_t is passed instead.
3700 ///
3701 /// Unlike @ref visit, this function also passes an extra meta data value
3702 /// when invoking the visitor. This meta data object provides `constexpr`
3703 /// information about the type and index of the value being visited. The ok
3704 /// value has index 0 and the error value has index 1. This object has the
3705 /// the API shown below.
3706 ///
3707 /// ```
3708 /// struct alternative_info {
3709 /// // index of the alternative (ok == 0, error == 1)
3710 /// static inline constexpr size_t index = ...;
3711 ///
3712 /// // type of the alternative (ok == T, error == E)
3713 /// using type = ...;
3714 ///
3715 /// // helper function for forwarding non-const alternative values
3716 /// // without needing to provide a template argument.
3717 /// static constexpr decltype(auto) forward(...);
3718 /// }
3719 /// ```
3720 ///
3721 /// Note that the @ref overload function can be helpful for defining a
3722 /// visitor inline.
3723 ///
3724 /// ## Example
3725 /// ```
3726 /// const result<int, std::string> res1{42};
3727 /// const result<int, std::string> res2{in_place_error, "oh no"};
3728 ///
3729 /// std::move(res1).visit_informed([](auto&& value, auto info) {
3730 /// if constexpr (info.index == 0) { // ok
3731 /// assert(value == 42);
3732 /// } else if constexpr (info.index == 1) { // error
3733 /// assert(false);
3734 /// }
3735 /// });
3736 ///
3737 /// std::move(res2).visit_informed([](auto&& value, auto info) {
3738 /// if constexpr (info.index == 0) { // ok
3739 /// assert(false);
3740 /// } else if constexpr (info.index == 1) { // error
3741 /// assert(value == "oh no");
3742 /// }
3743 /// });
3744 /// ```
3745 template <typename V>
3746 constexpr
3747 #ifndef DOXYGEN
3748 decltype(auto)
3749 #else
3750 DEDUCED
3751 #endif
3752 visit_informed(V&& visitor) const&& {
3753 return std::move(*this).res_().visit_informed(std::forward<V>(visitor));
3754 }
3755
3756 /// @brief Swaps two @ref result instances
3757 ///
3758 /// @details
3759 /// If both @ref result instances contain an ok value or both contain an
3760 /// error value, the values are swapped directly. If the two @ref result
3761 /// instances do not contain the same kind of value, the values are moved
3762 /// out of the @ref results temporarily, the old values are destroyed, and
3763 /// new values a move constructed in to the opposite @ref result.
3764 ///
3765 /// ## Example
3766 /// ```
3767 /// result<int, std::string> res1{42};
3768 /// result<int, std::string> res2{in_place_error, "oh no"};
3769 ///
3770 /// res1.swap(res2);
3771 ///
3772 /// assert(res1.is_error());
3773 /// assert(res1.error() == "oh no");
3774 ///
3775 /// assert(res2.is_ok());
3776 /// assert(*res2 == 42);
3777 /// ```
3778 constexpr void swap(result& other)
3779 #ifndef DOXYGEN
3780 noexcept(std::is_nothrow_swappable_v<variant<T, E>>)
3781 #else
3782 CONDITIONALLY_NOEXCEPT
3783 #endif
3784 {
3785 res_().swap(other.res_);
3786 }
3787 };
3788
3789 /// @relates result
3790 /// @brief Gets a @ref result value by index, as if it were a @ref variant
3791 ///
3792 /// @details
3793 /// This function is provided to make @ref result generically compatible with
3794 /// @ref variant. This function treats `result<T, E>` as if it were
3795 /// `variant<T, E>`, where index 0 is `T` and index 1 is `E`.
3796 ///
3797 /// ## Example
3798 /// ```
3799 /// result<int, std::string> res1{42};
3800 /// result<int, std::string> res2{in_place_error, "oh no"};
3801 ///
3802 /// assert(get<0>(res1) == 42);
3803 /// assert(get<1>(res2) == "oh no");
3804 /// ```
3805 ///
3806 /// @tparam IDX The "alternative" index
3807 ///
3808 /// @param res The @ref result to access
3809 ///
3810 /// @return A reference to the accessed "alternative"
3811 ///
3812 /// @throws bad_result_access Thrown if the @ref result does not contain the
3813 /// matching index.
3814 template <size_t IDX, typename T, typename E>
3815 constexpr
3816 #ifndef DOXYGEN
3817 typename detail::traits<detail::select_t<IDX, T, E>>::reference
3818 #else
3819 REFERENCE
3820 #endif
3821 get(result<T, E>& res) {
3822 return get<IDX>(res.res_);
3823 }
3824
3825 /// @relates result
3826 /// @brief Gets a @ref result value by index, as if it were a @ref variant
3827 ///
3828 /// @details
3829 /// This function is provided to make @ref result generically compatible with
3830 /// @ref variant. This function treats `result<T, E>` as if it were
3831 /// `variant<T, E>`, where index 0 is `T` and index 1 is `E`.
3832 ///
3833 /// ## Example
3834 /// ```
3835 /// const result<int, std::string> res1{42};
3836 /// const result<int, std::string> res2{in_place_error, "oh no"};
3837 ///
3838 /// assert(get<0>(res1) == 42);
3839 /// assert(get<1>(res2) == "oh no");
3840 /// ```
3841 ///
3842 /// @tparam IDX The "alternative" index
3843 ///
3844 /// @param res The @ref result to access
3845 ///
3846 /// @return A const reference to the accessed "alternative"
3847 ///
3848 /// @throws bad_result_access Thrown if the @ref result does not contain the
3849 /// matching index.
3850 template <size_t IDX, typename T, typename E>
3851 constexpr
3852 #ifndef DOXYGEN
3853 typename detail::traits<detail::select_t<IDX, T, E>>::const_reference
3854 #else
3855 CONST_REFERENCE
3856 #endif
3857 get(const result<T, E>& res) {
3858 return get<IDX>(res.res_);
3859 }
3860
3861 /// @relates result
3862 /// @brief Gets a @ref result value by index, as if it were a @ref variant
3863 ///
3864 /// @details
3865 /// This function is provided to make @ref result generically compatible with
3866 /// @ref variant. This function treats `result<T, E>` as if it were
3867 /// `variant<T, E>`, where index 0 is `T` and index 1 is `E`.
3868 ///
3869 /// ## Example
3870 /// ```
3871 /// result<int, std::string> res1{42};
3872 /// result<int, std::string> res2{in_place_error, "oh no"};
3873 ///
3874 /// assert(get<0>(std::move(res1)) == 42);
3875 /// assert(get<1>(std::move(res2)) == "oh no");
3876 /// ```
3877 ///
3878 /// @tparam IDX The "alternative" index
3879 ///
3880 /// @param res The @ref result to access
3881 ///
3882 /// @return An rvalue of the accessed "alternative"
3883 ///
3884 /// @throws bad_result_access Thrown if the @ref result does not contain the
3885 /// matching index.
3886 template <size_t IDX, typename T, typename E>
3887 constexpr
3888 #ifndef DOXYGEN
3889 typename detail::traits<detail::select_t<IDX, T, E>>::rvalue_reference
3890 #else
3891 RVALUE_REFERENCE
3892 #endif
3893 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
3894 get(result<T, E>&& res) {
3895 return get<IDX>(std::move(res.res_));
3896 }
3897
3898 /// @relates result
3899 /// @brief Gets a @ref result value by index, as if it were a @ref variant
3900 ///
3901 /// @details
3902 /// This function is provided to make @ref result generically compatible with
3903 /// @ref variant. This function treats `result<T, E>` as if it were
3904 /// `variant<T, E>`, where index 0 is `T` and index 1 is `E`.
3905 ///
3906 /// ## Example
3907 /// ```
3908 /// const result<int, std::string> res1{42};
3909 /// const result<int, std::string> res2{in_place_error, "oh no"};
3910 ///
3911 /// assert(get<0>(std::move(res1)) == 42);
3912 /// assert(get<1>(std::move(res2)) == "oh no");
3913 /// ```
3914 ///
3915 /// @tparam IDX The "alternative" index
3916 ///
3917 /// @param res The @ref result to access
3918 ///
3919 /// @return A const rvalue of the accessed "alternative"
3920 ///
3921 /// @throws bad_result_access Thrown if the @ref result does not contain the
3922 /// matching index.
3923 template <size_t IDX, typename T, typename E>
3924 constexpr
3925 #ifndef DOXYGEN
3926 typename detail::traits<detail::select_t<IDX, T, E>>::const_rvalue_reference
3927 #else
3928 CONST_RVALUE_REFERENCE
3929 #endif
3930 get(const result<T, E>&& res) {
3931 return get<IDX>(std::move(res.res_));
3932 }
3933
3934 /// @relates result
3935 /// @brief Gets a @ref result value by type, as if it were a @ref variant
3936 ///
3937 /// @details
3938 /// This fucntion is provided to make @ref result generically compatible with
3939 /// @ref variant. This function treats `result<T, E>` as if it were
3940 /// `variant<T, E>`.
3941 ///
3942 /// This function only participates in overload resolution if `T` and `E` are
3943 /// distinct types, in order to avoid ambiguity.
3944 ///
3945 /// ## Example
3946 /// ```
3947 /// result<int, std::string> res1{42};
3948 /// result<int, std::string> res2{in_place_error, "oh no"};
3949 ///
3950 /// assert(get<int>(res1) == 42);
3951 /// assert(get<std::string>(res2) == "oh no");
3952 /// ```
3953 ///
3954 /// @tparam U The "alternative" type
3955 ///
3956 /// @param res The @ref result to access
3957 ///
3958 /// @return A reference to the accessed "alternative"
3959 ///
3960 /// @throws bad_result_access Thrown if the @ref result does not contain the
3961 /// matching index.
3962 template <typename U, typename T, typename E>
3963 #ifndef DOXYGEN
3964 requires(std::is_same_v<U, T> || std::is_same_v<U, E>)
3965 #endif
3966 constexpr
3967 #ifndef DOXYGEN
3968 typename detail::traits<U>::reference
3969 #else
3970 REFERENCE
3971 #endif
3972 get(result<T, E>& res) {
3973 return get<U>(res.res_);
3974 }
3975
3976 /// @relates result
3977 /// @brief Gets a @ref result value by type, as if it were a @ref variant
3978 ///
3979 /// @details
3980 /// This fucntion is provided to make @ref result generically compatible with
3981 /// @ref variant. This function treats `result<T, E>` as if it were
3982 /// `variant<T, E>`.
3983 ///
3984 /// This function only participates in overload resolution if `T` and `E` are
3985 /// distinct types, in order to avoid ambiguity.
3986 ///
3987 /// ## Example
3988 /// ```
3989 /// const result<int, std::string> res1{42};
3990 /// const result<int, std::string> res2{in_place_error, "oh no"};
3991 ///
3992 /// assert(get<int>(res1) == 42);
3993 /// assert(get<std::string>(res2) == "oh no");
3994 /// ```
3995 ///
3996 /// @tparam U The "alternative" type
3997 ///
3998 /// @param res The @ref result to access
3999 ///
4000 /// @return A const reference to the accessed "alternative"
4001 ///
4002 /// @throws bad_result_access Thrown if the @ref result does not contain the
4003 /// matching index.
4004 template <typename U, typename T, typename E>
4005 #ifndef DOXYGEN
4006 requires(std::is_same_v<U, T> || std::is_same_v<U, E>)
4007 #endif
4008 constexpr
4009 #ifndef DOXYGEN
4010 typename detail::traits<U>::const_reference
4011 #else
4012 CONST_REFERENCE
4013 #endif
4014 get(const result<T, E>& res) {
4015 return get<U>(res.res_);
4016 }
4017
4018 /// @relates result
4019 /// @brief Gets a @ref result value by type, as if it were a @ref variant
4020 ///
4021 /// @details
4022 /// This fucntion is provided to make @ref result generically compatible with
4023 /// @ref variant. This function treats `result<T, E>` as if it were
4024 /// `variant<T, E>`.
4025 ///
4026 /// This function only participates in overload resolution if `T` and `E` are
4027 /// distinct types, in order to avoid ambiguity.
4028 ///
4029 /// ## Example
4030 /// ```
4031 /// result<int, std::string> res1{42};
4032 /// result<int, std::string> res2{in_place_error, "oh no"};
4033 ///
4034 /// assert(get<int>(std::move(res1)) == 42);
4035 /// assert(get<std::string>(std::move(res2)) == "oh no");
4036 /// ```
4037 ///
4038 /// @tparam U The "alternative" type
4039 ///
4040 /// @param res The @ref result to access
4041 ///
4042 /// @return An rvalue of the accessed "alternative"
4043 ///
4044 /// @throws bad_result_access Thrown if the @ref result does not contain the
4045 /// matching index.
4046 template <typename U, typename T, typename E>
4047 #ifndef DOXYGEN
4048 requires(std::is_same_v<U, T> || std::is_same_v<U, E>)
4049 #endif
4050 constexpr
4051 #ifndef DOXYGEN
4052 typename detail::traits<U>::rvalue_reference
4053 #else
4054 RVALUE_REFERENCE
4055 #endif
4056 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
4057 get(result<T, E>&& res) {
4058 return get<U>(std::move(res.res_));
4059 }
4060
4061 /// @relates result
4062 /// @brief Gets a @ref result value by type, as if it were a @ref variant
4063 ///
4064 /// @details
4065 /// This fucntion is provided to make @ref result generically compatible with
4066 /// @ref variant. This function treats `result<T, E>` as if it were
4067 /// `variant<T, E>`.
4068 ///
4069 /// This function only participates in overload resolution if `T` and `E` are
4070 /// distinct types, in order to avoid ambiguity.
4071 ///
4072 /// ## Example
4073 /// ```
4074 /// const result<int, std::string> res1{42};
4075 /// const result<int, std::string> res2{in_place_error, "oh no"};
4076 ///
4077 /// assert(get<int>(std::move(res1)) == 42);
4078 /// assert(get<std::string>(std::move(res2)) == "oh no");
4079 /// ```
4080 ///
4081 /// @tparam U The "alternative" type
4082 ///
4083 /// @param res The @ref result to access
4084 ///
4085 /// @return A const rvalue of the accessed "alternative"
4086 ///
4087 /// @throws bad_result_access Thrown if the @ref result does not contain the
4088 /// matching index.
4089 template <typename U, typename T, typename E>
4090 #ifndef DOXYGEN
4091 requires(std::is_same_v<U, T> || std::is_same_v<U, E>)
4092 #endif
4093 constexpr
4094 #ifndef DOXYGEN
4095 typename detail::traits<U>::const_rvalue_reference
4096 #else
4097 CONST_RVALUE_REFERENCE
4098 #endif
4099 get(const result<T, E>&& res) {
4100 return get<U>(std::move(res.res_));
4101 }
4102
4103 /// @relates result
4104 /// @brief Compares two @ref result instances for equality
4105 ///
4106 /// @details
4107 /// Returns true if both @ref result instances either both contain ok values or
4108 /// both contain error values, and the values compare equal.
4109 ///
4110 /// ## Example
4111 /// ```
4112 /// result<int, std::string> res1{42};
4113 /// result<unsigned int, const char*> res2{42};
4114 ///
4115 /// assert(res1 == res2);
4116 /// ```
4117 template <typename T, typename E, typename U, typename V>
4118 #ifndef DOXYGEN
4119 requires(std::is_void_v<T> == std::is_void_v<U> &&
4120 std::is_void_v<E> == std::is_void_v<V>)
4121 #endif
4122 constexpr bool operator==(const result<T, E>& lhs, const result<U, V>& rhs) {
4123 if (lhs.has_value()) {
4124 if constexpr (std::is_void_v<T>) {
4125 return rhs.has_value();
4126 } else {
4127 if (rhs.has_value()) {
4128 return *lhs == *rhs;
4129 } else {
4130 return false;
4131 }
4132 }
4133 } else {
4134 if constexpr (std::is_void_v<E>) {
4135 return !rhs.has_value();
4136 } else {
4137 if (rhs.has_value()) {
4138 return false;
4139 } else {
4140 return lhs.error() == rhs.error();
4141 }
4142 }
4143 }
4144 }
4145
4146 /// @relates result
4147 /// @brief Compares a @ref result with a plain value for equality
4148 ///
4149 /// @details
4150 /// This function return true if the @ref result contains an ok value and the
4151 /// ok value compares equal with the plain value.
4152 ///
4153 /// ## Example
4154 /// ```
4155 /// result<int, std::string> res1{42};
4156 /// result<int, std::string> res2{in_place_error, "oh no"};
4157 ///
4158 /// assert(res1 == 42);
4159 /// assert(res2 != 42);
4160 /// ```
4161 template <typename T, typename E, typename U>
4162 constexpr bool operator==(const result<T, E>& lhs, const U& rhs) {
4163 return lhs.has_value() && *lhs == rhs;
4164 }
4165
4166 /// @relates result
4167 /// @brief Compares a @ref result with a plain value for equality
4168 ///
4169 /// @details
4170 /// This function return true if the @ref result contains an ok value and the
4171 /// ok value compares equal with the plain value.
4172 ///
4173 /// ## Example
4174 /// ```
4175 /// result<int, std::string> res1{42};
4176 /// result<int, std::string> res2{in_place_error, "oh no"};
4177 ///
4178 /// assert(42 == res1);
4179 /// assert(42 != res2);
4180 /// ```
4181 template <typename T, typename E, typename U>
4182 constexpr bool operator==(const U& lhs, const result<T, E>& rhs) {
4183 return rhs.has_value() && lhs == *rhs;
4184 }
4185
4186 /// @relates result
4187 /// @brief Swaps two @ref result instances
4188 ///
4189 /// @details
4190 /// If both @ref result instances contain an ok value or both contain an
4191 /// error value, the values are swapped directly. If the two @ref result
4192 /// instances do not contain the same kind of value, the values are moved
4193 /// out of the @ref results temporarily, the old values are destroyed, and
4194 /// new values a move constructed in to the opposite @ref result.
4195 ///
4196 /// ## Example
4197 /// ```
4198 /// result<int, std::string> res1{42};
4199 /// result<int, std::string> res2{in_place_error, "oh no"};
4200 ///
4201 /// swap(res1, res2);
4202 ///
4203 /// assert(res1.is_error());
4204 /// assert(res1.error() == "oh no");
4205 ///
4206 /// assert(res2.is_ok());
4207 /// assert(*res2 == 42);
4208 /// ```
4209 template <typename T, typename E>
4210 constexpr void swap(result<T, E>& a, result<T, E>& b)
4211 #ifndef DOXYGEN
4212 noexcept(std::is_nothrow_swappable_v<variant<T, E>>)
4213 #else
4214 CONDITIONALLY_NOEXCEPT
4215 #endif
4216 {
4217 a.swap(b);
4218 }
4219
4220 /// @relates result
4221 /// @brief Creates an ok valued @ref result, constructed in place
4222 ///
4223 /// @details
4224 /// Similar to STL functions like `std::make_unique` and `std::make_optional`,
4225 /// this function is provided a template argument to specify what contained
4226 /// type should be constructed, and then is passed arguments that are
4227 /// forwarded to the constructor of the contained type.
4228 ///
4229 /// ## Example
4230 /// ```
4231 /// result<std::string, void> make_string() {
4232 /// // returns a result<std::string, never> which gets converted to
4233 /// // a result<std::string, void>
4234 /// return ok<std::string>("hello");
4235 /// }
4236 /// ```
4237 template <typename T, typename... Args>
4238 12 constexpr result<T, never> ok(Args&&... args) {
4239 12 return result<T, never>{std::in_place, std::forward<Args>(args)...};
4240 }
4241
4242 /// @relates result
4243 /// @brief Creates an ok valued @ref result, constructed in place
4244 ///
4245 /// @details
4246 /// Similar to STL functions like `std::make_unique` and `std::make_optional`,
4247 /// this function is provided a template argument to specify what contained
4248 /// type should be constructed, and then is passed arguments that are
4249 /// forwarded to the constructor of the contained type.
4250 ///
4251 /// ## Example
4252 /// ```
4253 /// result<std::vector<int>, void> make_nums() {
4254 /// // returns a result<std::vector<int>, never> which gets converted
4255 /// // to a result<std::vector<int>, void>
4256 /// return ok<std::vector<int>>({1, 2, 3, 4, 5});
4257 /// }
4258 /// ```
4259 template <typename T, typename U, typename... Args>
4260 constexpr result<T, never> ok(std::initializer_list<U> ilist, Args&&... args) {
4261 return result<T, never>{std::in_place, ilist, std::forward<Args>(args)...};
4262 }
4263
4264 /// @relates result
4265 /// @brief Creates an error valued @ref result, constructed in place
4266 ///
4267 /// @details
4268 /// Similar to STL functions like `std::make_unique` and `std::make_optional`,
4269 /// this function is provided a template argument to specify what contained
4270 /// error type should be constructed, and then is passed arguments that are
4271 /// forwarded to the constructor of the contained error type.
4272 ///
4273 /// ## Example
4274 /// ```
4275 /// result<void, std::string> ensure_positive(int value) {
4276 /// if (value < 0) {
4277 /// return error<std::string>("value is negative");
4278 /// }
4279 /// return value;
4280 /// }
4281 /// ```
4282 template <typename E, typename... Args>
4283 20 constexpr result<never, E> error(Args&&... args) {
4284 20 return result<never, E>{in_place_error, std::forward<Args>(args)...};
4285 }
4286
4287 /// @relates result
4288 /// @brief Creates an error valued @ref result, constructed in place
4289 ///
4290 /// @details
4291 /// Similar to STL functions like `std::make_unique` and `std::make_optional`,
4292 /// this function is provided a template argument to specify what contained
4293 /// error type should be constructed, and then is passed arguments that are
4294 /// forwarded to the constructor of the contained error type.
4295 ///
4296 /// ## Example
4297 /// ```
4298 /// result<void, std::vector<int>> ilist_error_example() {
4299 /// // returns a result<never, std::vector<int>> which gets converted
4300 /// // to a result<void, std::vector<int>>
4301 /// return error<std::vector<int>>({1, 2, 3, 4, 5});
4302 /// }
4303 /// ```
4304 template <typename E, typename U, typename... Args>
4305 constexpr result<never, E> error(std::initializer_list<U> ilist, Args&&... args) {
4306 return result<never, E>{in_place_error, ilist, std::forward<Args>(args)...};
4307 }
4308
4309 /// @private
4310 template <typename T, typename E>
4311 requires(std::is_base_of_v<never, std::remove_cvref_t<T>> &&
4312 std::is_base_of_v<never, std::remove_cvref_t<E>>)
4313 class result<T, E> : public never {};
4314
4315 } // namespace sumty
4316
4317 #endif
4318