@@ -497,7 +497,7 @@ class Result {
497497 return std::visit ([](auto && arg) -> traits::and_then_return_t <Self, F> {
498498 // even though this conditional is impossible, it's necessary to stop the compiler
499499 // from thinking that ReturnType could be constructed with std::monostate
500- if constexpr (std::is_same_v <std::monostate, std::remove_cvref_t <decltype (arg)>>) {
500+ if constexpr (std::same_as <std::monostate, std::remove_cvref_t <decltype (arg)>>) {
501501 throw std::logic_error (" This exception is unreachable" );
502502 } else {
503503 return std::forward<decltype (arg)>(arg);
@@ -511,6 +511,9 @@ class Result {
511511 /* *
512512 * @brief or_else monadic function.
513513 *
514+ * @note wrappers are used for the requires clause in order to avoid the use of fold
515+ * expressions, as fold expressions significantly complicates error messages
516+ *
514517 * constraints:
515518 * - Callable must be invocable with at least one error type as an argument
516519 * - If the callable is invocable, it must always return the same type given different parameter
@@ -535,12 +538,14 @@ class Result {
535538 // Result instance
536539 && traits::AllValueTypeMatch<Self, traits::or_else_return_t <Self, F, Errs>...>
537540 constexpr auto or_else (this Self&& self, F&& f) {
541+ using namespace traits ;
542+
538543 // the return type is the same as the return type of the callable, unless the callable
539544 // returns void. In that case, the return type is Self with cv-refs removed
540545 using CallableReturnType =
541- traits:: first_type_that_satisfies_t <traits:: invocable_indirect_v<F, Self>, Errs...>;
546+ first_type_that_satisfies_t <invocable_indirect_v<F, Self>, Errs...>;
542547 using ReturnType = std::conditional_t <
543- traits:: IsResult<CallableReturnType>,
548+ IsResult<CallableReturnType>,
544549 CallableReturnType,
545550 std::remove_cvref_t <Self>>;
546551
@@ -555,7 +560,7 @@ class Result {
555560 // even though this condition is impossible, it's necessary. Otherwise the
556561 // compiler will compile a branch where f is invoked with an unsupported argument
557562 // type
558- if constexpr (!traits:: Invocable<Self, F, decltype ((arg))>
563+ if constexpr (!Invocable<Self, F, decltype ((arg))>
559564 || std::
560565 is_same_v<std::monostate, std::remove_cvref_t <decltype (arg)>>) {
561566 throw std::logic_error (" This exception is unreachable" );
@@ -571,7 +576,7 @@ class Result {
571576 // even though this condition is impossible, it's necessary. Otherwise the
572577 // compiler will compile a branch where f is invoked with an unsupported argument
573578 // type
574- if constexpr (!traits:: Invocable<Self, F, decltype ((arg))>
579+ if constexpr (!Invocable<Self, F, decltype ((arg))>
575580 || std::is_same_v<std::monostate, std::remove_cvref_t <decltype (arg)>>) {
576581 throw std::logic_error (" This exception is unreachable" );
577582 } else {
@@ -624,12 +629,6 @@ operator==(const Result<LhsT, LhsErrs...>& lhs, const Result<RhsT, RhsErrs...>&
624629template <traits::IsResultError... Errs>
625630 requires (sizeof ...(Errs) > 0 )
626631class Result <void , Errs...> {
627- private:
628- // or_else return type helper
629- template <typename Self, typename F, typename E>
630- using or_else_return_t =
631- std::invoke_result_t <F, decltype ((std::get<E>(std::declval<Self>().error)))>;
632-
633632 public:
634633 using value_type = void ;
635634 using error_types = traits::type_pack<Errs...>;
@@ -717,33 +716,77 @@ class Result<void, Errs...> {
717716 /* *
718717 * @brief or_else monadic function.
719718 *
720- * The callable must be able to take a perfectly forwarded error that may be contained by this
721- * Result instance. The callable must be able to return a Result containing any error type that
722- * may be passed to it. The normal value type of the Result returned by the callable must be the
723- * same as the normal value type of this Result instance.
719+ * @note wrappers are used for the requires clause in order to avoid the use of fold
720+ * expressions, as fold expressions significantly complicates error messages
721+ *
722+ * constraints:
723+ * - Callable must be invocable with at least one error type as an argument
724+ * - If the callable is invocable, it must always return the same type given different parameter
725+ * types
726+ * - The callable is only allowed to return a Result, or void
727+ * - If a Result is returned, it must have the same value type as this Result instance
728+ * - The return type of the callable must be the same for all possible arguments it may be
729+ * called with.
724730 *
725731 * @tparam Self deduced self type
726732 * @tparam F the type of the callable
727733 * @param self the current Result instance
728734 * @param f the callable
729735 */
730736 template <typename Self, typename F>
731- requires (std::invocable<F, decltype ((std::get<Errs>(std::declval<Self>().error)))> && ...)
732- && (traits::IsResult<or_else_return_t <Self, F, Errs>> && ...)
733- && (traits::AllSame<or_else_return_t <Self, F, Errs>...>)
734- && (std::same_as<void , typename or_else_return_t <Self, F, Errs>::value_type> && ...)
737+ requires traits::AnyInvocable<Self, F, Errs...>
738+ // the callable must always return the same type (if it's invocable)
739+ && traits::AllSame<traits::or_else_return_t <Self, F, Errs>...>
740+ // the callable must return a Result or void (if it's invocable)
741+ && traits::AllResultOrVoid<Self, F, Errs...>
742+ // if the callable returns a Result, it must have the same value type as this
743+ // Result instance
744+ && traits::AllValueTypeMatch<Self, traits::or_else_return_t <Self, F, Errs>...>
735745 constexpr auto or_else (this Self&& self, F&& f) {
736- using ReturnType = or_else_return_t <Self, F, std::tuple_element_t <0 , std::tuple<Errs...>>>;
737- // if there isn't an error, return
738- return ReturnType ();
739- // otherwise, invoke the given lambda
746+ using namespace traits ;
747+
748+ // the return type is the same as the return type of the callable, unless the callable
749+ // returns void. In that case, the return type is Self with cv-refs removed
750+ using CallableReturnType =
751+ first_type_that_satisfies_t <invocable_indirect_v<F, Self>, Errs...>;
752+ using ReturnType = std::conditional_t <
753+ IsResult<CallableReturnType>,
754+ CallableReturnType,
755+ std::remove_cvref_t <Self>>;
756+
757+ // if there isn't an error, return the value
758+ if (!self.has_error ()) {
759+ return ReturnType (std::forward<Self>(self).value );
760+ }
761+
762+ // if the callable returns void
763+ if constexpr (std::same_as<void , CallableReturnType>) {
764+ return std::visit ([&f](auto && arg) -> ReturnType {
765+ // even though this condition is impossible, it's necessary. Otherwise the
766+ // compiler will compile a branch where f is invoked with an unsupported argument
767+ // type
768+ if constexpr (!Invocable<Self, F, decltype ((arg))>
769+ || std::
770+ is_same_v<std::monostate, std::remove_cvref_t <decltype (arg)>>) {
771+ throw std::logic_error (" This exception is unreachable" );
772+ } else {
773+ std::invoke (f, std::forward<decltype (arg)>(arg));
774+ return std::forward<decltype (arg)>(arg);
775+ }
776+ }, std::forward<Self>(self).error );
777+ }
778+
779+ // if the callable returns Result
740780 return std::visit ([&f](auto && arg) -> ReturnType {
741- // even though this conditional is impossible, it's necessary to stop the compiler from
742- // thinking that ReturnType could be constructed with std::monostate
743- if constexpr (std::is_same_v<std::monostate, std::remove_cvref_t <decltype (arg)>>) {
781+ // even though this condition is impossible, it's necessary. Otherwise the
782+ // compiler will compile a branch where f is invoked with an unsupported argument
783+ // type
784+ if constexpr (!Invocable<Self, F, decltype ((arg))>
785+ || std::is_same_v<std::monostate, std::remove_cvref_t <decltype (arg)>>) {
744786 throw std::logic_error (" This exception is unreachable" );
745787 } else {
746- return std::invoke (f, arg);
788+ std::invoke (f, std::forward<decltype (arg)>(arg));
789+ return std::forward<decltype (arg)>(arg);
747790 }
748791 }, std::forward<Self>(self).error );
749792 }
0 commit comments