diff options
author | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2025-02-26 20:01:45 +0100 |
---|---|---|
committer | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2025-02-26 20:01:45 +0100 |
commit | 38ab48b1882f36ed7eb7e50c4fb46ce5d376fbc3 (patch) | |
tree | 63da65e8137f8f075ab33776d2a812bb31d86845 /asl | |
parent | 8034ce643d36e8cbe4c4d6bc9e154aaf2eb08597 (diff) |
Fix some deducing-this & functional stuff, add invocable concept
Diffstat (limited to 'asl')
-rw-r--r-- | asl/base/defer.hpp | 6 | ||||
-rw-r--r-- | asl/base/functional.hpp | 19 | ||||
-rw-r--r-- | asl/base/functional_tests.cpp | 24 | ||||
-rw-r--r-- | asl/types/option.hpp | 25 |
4 files changed, 47 insertions, 27 deletions
diff --git a/asl/base/defer.hpp b/asl/base/defer.hpp index b6d52af..e881d8a 100644 --- a/asl/base/defer.hpp +++ b/asl/base/defer.hpp @@ -6,8 +6,7 @@ namespace asl
{
-// @Todo Add invokable check
-template<typename Callback>
+template<invocable Callback>
class DeferCallback
{
Callback m_callback;
@@ -36,8 +35,7 @@ public: struct DeferFactory
{
- // @Todo Add invokable check
- template<typename Callback>
+ template<invocable Callback>
DeferCallback<Callback> operator<<(Callback&& callback) const
{
return DeferCallback<Callback>(ASL_FWD(callback));
diff --git a/asl/base/functional.hpp b/asl/base/functional.hpp index d820bce..b4b5312 100644 --- a/asl/base/functional.hpp +++ b/asl/base/functional.hpp @@ -7,6 +7,7 @@ namespace asl { template<typename... Args, typename C> constexpr auto invoke(is_func auto C::* f, auto&& self, Args&&... args) + -> decltype((self.*f)(ASL_FWD(args)...)) requires requires { (self.*f)(ASL_FWD(args)...); } @@ -16,6 +17,7 @@ constexpr auto invoke(is_func auto C::* f, auto&& self, Args&&... args) template<typename... Args, typename C> constexpr auto invoke(is_func auto C::* f, auto* self, Args&&... args) + -> decltype((self->*f)(ASL_FWD(args)...)) requires requires { (self->*f)(ASL_FWD(args)...); } @@ -25,6 +27,7 @@ constexpr auto invoke(is_func auto C::* f, auto* self, Args&&... args) template<typename... Args, typename C> constexpr auto invoke(is_object auto C::* m, auto&& self, Args&&...) + -> decltype(self.*m) requires ( sizeof...(Args) == 0 && requires { self.*m; } @@ -35,6 +38,7 @@ constexpr auto invoke(is_object auto C::* m, auto&& self, Args&&...) template<typename... Args, typename C> constexpr auto invoke(is_object auto C::* m, auto* self, Args&&...) + -> decltype(self->*m) requires ( sizeof...(Args) == 0 && requires { self->*m; } @@ -45,6 +49,7 @@ constexpr auto invoke(is_object auto C::* m, auto* self, Args&&...) template<typename... Args> constexpr auto invoke(auto&& f, Args&&... args) + -> decltype(f(ASL_FWD(args)...)) requires requires { f(ASL_FWD(args)...); } @@ -52,14 +57,22 @@ constexpr auto invoke(auto&& f, Args&&... args) return ASL_FWD(f)(ASL_FWD(args)...); } -template<typename F> struct _result_of_helper; +template<typename Void, typename F, typename... Args> +struct _invoke_result_helper; template<typename R, typename... Args> -struct _result_of_helper<R(Args...)> +struct _invoke_result_helper<void, R, Args...> { using type = decltype(invoke(declval<R>(), declval<Args>()...)); }; -template<typename F> using result_of_t = _result_of_helper<F>::type; +template<typename F, typename... Args> +using invoke_result_t = _invoke_result_helper<void, F, Args...>::type; + +template<typename F, typename... Args> +concept invocable = requires (F&& f, Args&&... args) +{ + invoke(ASL_FWD(f), ASL_FWD(args)...); +}; } // namespace asl diff --git a/asl/base/functional_tests.cpp b/asl/base/functional_tests.cpp index 92c5c7b..991c3c1 100644 --- a/asl/base/functional_tests.cpp +++ b/asl/base/functional_tests.cpp @@ -24,11 +24,25 @@ static int some_func1(int x) { return x + 1; } [[maybe_unused]] static float some_func1(float x) { return x + 1; } static int some_func2(int x, int b) { return x + b; } -static_assert(asl::same_as<asl::result_of_t<Functor()>, int64_t>); -static_assert(asl::same_as<asl::result_of_t<Functor(int)>, int>); -static_assert(asl::same_as<asl::result_of_t<decltype(static_cast<float(*)(float)>(some_func1))(float)>, float>); -static_assert(asl::same_as<asl::result_of_t<decltype(&HasFunction::do_something)(HasFunction, int, float)>, void>); -static_assert(asl::same_as<asl::result_of_t<decltype(&HasMember::member)(HasMember)>, int>); +static_assert(asl::same_as<asl::invoke_result_t<int()>, int>); +static_assert(asl::same_as<asl::invoke_result_t<int(float), float>, int>); +static_assert(asl::same_as<asl::invoke_result_t<Functor>, int64_t>); +static_assert(asl::same_as<asl::invoke_result_t<Functor, int>, int>); +static_assert(asl::same_as<asl::invoke_result_t<decltype(static_cast<float(*)(float)>(some_func1)), float>, float>); +static_assert(asl::same_as<asl::invoke_result_t<decltype(&HasFunction::do_something), HasFunction, int, float>, void>); +static_assert(asl::same_as<asl::invoke_result_t<decltype(&HasMember::member), const HasMember>, const int&>); + +static_assert(asl::invocable<int()>); +static_assert(!asl::invocable<int(), int>); +static_assert(asl::invocable<int(float), float>); +static_assert(!asl::invocable<int(float), int*>); +static_assert(asl::invocable<Functor>); +static_assert(asl::invocable<Functor, int>); +static_assert(!asl::invocable<Functor, void*>); +static_assert(asl::invocable<decltype(static_cast<float(*)(float)>(some_func1)), float>); +static_assert(asl::invocable<decltype(&HasFunction::do_something), HasFunction, int, float>); +static_assert(!asl::invocable<decltype(&HasFunction::do_something), HasFunction, int, int*>); +static_assert(asl::invocable<decltype(&HasMember::member), const HasMember>); ASL_TEST(invoke_member_function) { diff --git a/asl/types/option.hpp b/asl/types/option.hpp index e79c09c..b32483b 100644 --- a/asl/types/option.hpp +++ b/asl/types/option.hpp @@ -395,32 +395,27 @@ public: return value(); } - template< - typename F, - typename Self, - typename Result = result_of_t<F(copy_cref_t<Self&&, T>)> - > + template<typename F, typename Self> constexpr auto and_then(this Self&& self, F&& f) - requires is_option<Result> { + using Result = invoke_result_t<F, copy_cref_t<Self&&, T>>; + static_assert(is_option<Result>); + if (self.has_value()) { - return invoke(ASL_FWD(f), ASL_FWD_LIKE(decltype(self), ASL_FWD(self).value())); + return invoke(ASL_FWD(f), ASL_FWD(self).value()); } return Result{ asl::nullopt }; } - template< - typename F, - typename Self, - typename Result = result_of_t<F(copy_cref_t<Self&&, T>)> - > + template<typename F, typename Self> constexpr auto transform(this Self&& self, F&& f) { + using Result = invoke_result_t<F, copy_cref_t<Self&&, T>>; if (self.has_value()) { return option<un_cvref_t<Result>>{ - invoke(ASL_FWD(f), ASL_FWD_LIKE(decltype(self), ASL_FWD(self).value())) + invoke(ASL_FWD(f), ASL_FWD(self).value()) }; } return option<un_cvref_t<Result>>{ asl::nullopt }; @@ -428,14 +423,14 @@ public: template<typename F> constexpr option or_else(F&& f) const& - requires same_as<un_cvref_t<result_of_t<F()>>, option> + requires same_as<un_cvref_t<invoke_result_t<F>>, option> { return has_value() ? *this : invoke(ASL_FWD(f)); } template<typename F> constexpr option or_else(F&& f) && - requires same_as<un_cvref_t<result_of_t<F()>>, option> + requires same_as<un_cvref_t<invoke_result_t<F>>, option> { return has_value() ? ASL_MOVE(*this) : invoke(ASL_FWD(f)); } |