Skip to content

Commit faccaec

Browse files
committed
fix more Result constraints
1 parent 00122de commit faccaec

File tree

1 file changed

+17
-100
lines changed

1 file changed

+17
-100
lines changed

include/common/result.hpp

Lines changed: 17 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ class Result {
234234
* @param value Value to initialize the result with.
235235
*/
236236
template<typename U>
237-
requires std::convertible_to<T, U> && (!traits::IsResultError<U>)
237+
requires std::convertible_to<T, U> && (!traits::is_in_pack_v<U, std::monostate, Errs...>)
238238
constexpr Result(U&& value)
239239
: error(std::monostate()),
240240
value(std::forward<U>(value)) {}
@@ -245,7 +245,7 @@ class Result {
245245
* @param error Error to store.
246246
* @note Requires T to have a defined sentinel value (via SentinelValue<T>).
247247
*/
248-
template<traits::IsResultError E>
248+
template<typename E>
249249
requires traits::is_in_pack_v<E, Errs...>
250250
constexpr Result(E&& error)
251251
: error(std::forward<E>(error)),
@@ -308,15 +308,14 @@ class Result {
308308
constexpr auto and_then(this Self&& self, F&& f)
309309
requires std::invocable<F, decltype(std::forward<Self>(self).value)>
310310
&& traits::is_result_v<and_then_return_t<Self, F>>
311-
&& traits::contains_all_v<
312-
typename and_then_return_t<Self, F>::error_types,
313-
typename Self::error_types>
311+
&& traits::
312+
contains_all_v<typename and_then_return_t<Self, F>::error_types, error_types>
314313
{
315314
// if there is an error, return said error immediately
316315
if (self.has_error()) {
317316
return std::visit([](auto&& var) -> and_then_return_t<Self, F> {
318317
return std::forward<decltype(var)>(var);
319-
}, std::forward<Self>(self));
318+
}, std::forward<Self>(self).error);
320319
}
321320
// otherwise, invoke the callable and return the result
322321
return std::invoke(f, std::forward<Self>(self).value);
@@ -377,8 +376,8 @@ class Result<void, Errs...> {
377376
* @tparam E Error type (must be in Errs).
378377
* @param error Error to store.
379378
*/
380-
template<traits::IsResultError E>
381-
requires traits::is_in_pack_v<E, Errs...>
379+
template<typename E>
380+
requires traits::is_in_pack_v<E, std::monostate, Errs...>
382381
constexpr Result(E&& error)
383382
: error(std::forward<E>(error)) {}
384383

@@ -396,11 +395,11 @@ class Result<void, Errs...> {
396395
* @param self the self object
397396
* @return the error type, wrapped in std::optional
398397
*/
399-
template<typename Self, traits::IsResultError E>
398+
template<traits::IsResultError E, typename Self>
400399
requires traits::is_in_pack_v<E, Errs...>
401-
constexpr auto&& get_error(this Self&& self) {
400+
constexpr auto get_error(this Self&& self) {
402401
if (std::holds_alternative<E>(self.error)) {
403-
return std::optional(std::holds_alternative<E>(std::forward<Self>(self).error));
402+
return std::optional<E>(std::get<E>(std::forward<Self>(self).error));
404403
} else {
405404
return std::optional<E>();
406405
}
@@ -429,103 +428,21 @@ class Result<void, Errs...> {
429428
* @param f the callable
430429
* @return return type of callable
431430
*/
432-
template<typename Self, typename F>
431+
template<std::invocable F, typename Self>
433432
constexpr auto and_then(this Self&& self, F&& f)
434-
requires std::invocable<F, void> && traits::is_result_v<std::invoke_result_t<F, void>>
433+
requires traits::is_result_v<std::invoke_result_t<F>>
435434
&& traits::
436-
contains_all_v<std::invoke_result_t<F, void>, typename Self::error_types>
435+
contains_all_v<typename std::invoke_result_t<F>::error_types, error_types>
437436
{
438437
// if there is an error, return said error immediately
439438
if (self.has_error()) {
440-
return std::visit([](auto&& var) -> std::invoke_result_t<F, void> {
439+
return std::visit([](auto&& var) -> std::invoke_result_t<F> {
441440
return std::forward<decltype(var)>(var);
442-
}, std::forward<Self>(self));
441+
}, std::forward<Self>(self).error);
443442
}
444443
// otherwise, invoke the callable and return the result
445-
return std::invoke(f, std::forward<Self>(self).value);
444+
return std::invoke(f);
446445
}
447446
};
448447

449-
} // namespace zest
450-
451-
namespace zest::test {
452-
453-
// Custom error types
454-
struct ErrorA : protected ResultError {};
455-
456-
struct ErrorB : protected ResultError {};
457-
458-
// Test callables for non-void Results
459-
constexpr auto return_rvalue = [](int&& x) -> Result<int, ErrorA, ErrorB> {
460-
return x * 2;
461-
};
462-
constexpr auto return_lvalue = [](int& x) -> Result<int, ErrorA, ErrorB> {
463-
return x * 2;
464-
};
465-
constexpr auto return_const = [](const int& x) -> Result<int, ErrorA, ErrorB> {
466-
return x * 2;
467-
};
468-
469-
// Test callables for void Results
470-
constexpr auto void_success = []() -> Result<void, ErrorA, ErrorB> {
471-
return {};
472-
};
473-
constexpr auto void_failure = []() -> Result<void, ErrorA, ErrorB> {
474-
return ErrorA{};
475-
};
476-
477-
// Compile-time test runner
478-
constexpr bool run_tests() {
479-
// Non-void Result tests
480-
{
481-
// Test lvalue forwarding
482-
Result<int, ErrorA, ErrorB> res{42};
483-
auto new_res = res.and_then(return_lvalue);
484-
if (new_res.has_error() || new_res.get_value() != 84)
485-
return false;
486-
487-
// Test const lvalue forwarding
488-
const Result<int, ErrorA, ErrorB> cres{42};
489-
auto cnew_res = cres.and_then(return_const);
490-
if (cnew_res.has_error() || cnew_res.get_value() != 84)
491-
return false;
492-
493-
// Test rvalue forwarding
494-
auto rnew_res = Result<int, ErrorA, ErrorB>{42}.and_then(return_rvalue);
495-
if (rnew_res.has_error() || rnew_res.get_value() != 84)
496-
return false;
497-
498-
// Test error propagation
499-
Result<int, ErrorA, ErrorB> err_res{ErrorA{}};
500-
auto err_new_res = err_res.and_then(return_lvalue);
501-
if (!err_new_res.has_error() || !err_new_res.get_error<ErrorA>())
502-
return false;
503-
}
504-
505-
// Void Result tests
506-
{
507-
// Test successful chain
508-
Result<void, ErrorA, ErrorB> vres;
509-
auto vnew_res = vres.and_then(void_success);
510-
if (vnew_res.has_error())
511-
return false;
512-
513-
// Test error propagation
514-
Result<void, ErrorA, ErrorB> verr_res{ErrorA{}};
515-
auto verr_new_res = verr_res.and_then(void_success);
516-
if (!verr_new_res.has_error() || !verr_new_res.get_error<ErrorA>())
517-
return false;
518-
519-
// Test new error in callback
520-
auto vfail_res = Result<void, ErrorA, ErrorB>{}.and_then(void_failure);
521-
if (!vfail_res.has_error() || !vfail_res.get_error<ErrorA>())
522-
return false;
523-
}
524-
525-
return true;
526-
}
527-
528-
// Compile-time test execution
529-
static_assert(run_tests(), "All tests passed");
530-
531-
} // namespace zest::test
448+
} // namespace zest

0 commit comments

Comments
 (0)