summaryrefslogtreecommitdiff
path: root/asl
diff options
context:
space:
mode:
authorSteven Le Rouzic <steven.lerouzic@gmail.com>2025-02-26 20:01:45 +0100
committerSteven Le Rouzic <steven.lerouzic@gmail.com>2025-02-26 20:01:45 +0100
commit38ab48b1882f36ed7eb7e50c4fb46ce5d376fbc3 (patch)
tree63da65e8137f8f075ab33776d2a812bb31d86845 /asl
parent8034ce643d36e8cbe4c4d6bc9e154aaf2eb08597 (diff)
Fix some deducing-this & functional stuff, add invocable concept
Diffstat (limited to 'asl')
-rw-r--r--asl/base/defer.hpp6
-rw-r--r--asl/base/functional.hpp19
-rw-r--r--asl/base/functional_tests.cpp24
-rw-r--r--asl/types/option.hpp25
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));
}