From e6a401f804c7a88d6a6664d1500852082271b395 Mon Sep 17 00:00:00 2001 From: Rafael Varago Date: Tue, 4 Mar 2025 16:25:15 +0100 Subject: [PATCH] Move templates from error policy into its methods This avoids repeating the refinement type when parameterising a refinement factory with a custom policy. E.g. from: `error::to_optional` to: `error::to_optional` (no more `` is required) --- include/rvarago/refined.hpp | 43 ++++++++++++++++++++++++------------- test/refined_test.cpp | 12 +++++------ 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/include/rvarago/refined.hpp b/include/rvarago/refined.hpp index 4f7b66b..5e14658 100644 --- a/include/rvarago/refined.hpp +++ b/include/rvarago/refined.hpp @@ -16,28 +16,36 @@ concept policy = requires(Policy p, Refinement refined) { typename Refinement::predicate_type; // On success. - { p.ok(refined) } -> std::same_as; + { + p.template ok(refined) + } -> std::same_as>; // On error. - { p.err() } -> std::same_as; + { + p.template err() + } -> std::same_as>; }; // Report errors as `std::optional`. -template struct to_optional { - using return_type = std::optional; +struct to_optional { + template using wrapper_type = std::optional; // Returns an engaged optional. - constexpr auto ok(Refinement refinement) const -> return_type { + template + constexpr auto ok(Refinement refinement) const -> wrapper_type { return std::optional{std::move(refinement)}; } // Returns nullopt. - constexpr auto err() const -> return_type { return std::nullopt; } + template + constexpr auto err() const -> wrapper_type { + return std::nullopt; + } }; // Report errors as exceptions. -template struct to_exception { - using return_type = Refinement; +struct to_exception { + template using wrapper_type = Refinement; struct refinement_exception : std::exception { const char *what() const noexcept override { @@ -46,13 +54,18 @@ template struct to_exception { }; // Returns argument unchanged. - constexpr auto ok(Refinement refinement) const -> return_type { + template + constexpr auto ok(Refinement refinement) const -> wrapper_type { return refinement; } // Throws a `refinement_exception`. - constexpr auto err() const -> return_type { throw refinement_exception{}; } + template + constexpr auto err() const -> wrapper_type { + throw refinement_exception{}; + } }; + } // namespace error // `refinement` constraints values `t: T` where `Pred{}(t)` holds. @@ -67,14 +80,14 @@ template Pred> struct refinement { // // If `pred(value)` holds, then produces a valid instance by delegating to // `policy.ok`. Else reports error via `policy.err`. - template > Policy = - error::to_optional>> + template > Policy = error::to_optional> static constexpr auto make(T value, Pred pred = {}, Policy policy = {}) - -> Policy::return_type { + -> Policy::template wrapper_type> { if (std::invoke(std::move(pred), value)) { - return policy.ok({refinement{std::move(value)}}); + return policy.template ok>( + {refinement{std::move(value)}}); } else { - return policy.err(); + return policy.template err>(); } } diff --git a/test/refined_test.cpp b/test/refined_test.cpp index 047cb8c..4a517e6 100644 --- a/test/refined_test.cpp +++ b/test/refined_test.cpp @@ -14,7 +14,7 @@ TEST_CASE( STATIC_REQUIRE(std::is_same_v>); STATIC_REQUIRE( - std::is_same_v>(0)), + std::is_same_v(0)), std::optional>); STATIC_REQUIRE(even::make(0)->value == 0); @@ -27,10 +27,10 @@ TEST_CASE("A to_exception policy should throw on invalid argument", "[error_policy][to_exception]") { STATIC_REQUIRE( - std::is_same_v< - decltype(even::make>(10)), even>); + std::is_same_v(10)), + even>); - STATIC_REQUIRE(even::make>(0).value == 0); - REQUIRE_THROWS_AS(even::make>(1), - refined::error::to_exception::refinement_exception); + STATIC_REQUIRE(even::make(0).value == 0); + REQUIRE_THROWS_AS(even::make(1), + refined::error::to_exception::refinement_exception); }