Improve implementation of invoke

This commit is contained in:
2025-03-26 18:54:54 +01:00
parent e034efe8bd
commit f19d93a69a
5 changed files with 82 additions and 51 deletions

View File

@ -9,56 +9,49 @@
namespace asl {
template<typename... Args, typename C>
constexpr auto invoke(is_func auto C::* f, auto&& self, Args&&... args)
-> decltype((self.*f)(std::forward<Args>(args)...))
requires requires {
(self.*f)(std::forward<Args>(args)...);
template<typename F, typename... Args>
constexpr auto invoke(F&& f, Args&&... args)
-> decltype(std::forward<F>(f)(std::forward<Args>(args)...))
requires (!is_member_ptr<un_cvref_t<F>>) && requires {
f(std::forward<Args>(args)...);
}
{
return std::forward<F>(f)(std::forward<Args>(args)...);
}
template<typename C>
constexpr auto&& invoke(auto C::* f, same_or_derived_from<C> auto&& arg)
{
return std::forward<decltype(arg)>(arg).*f;
}
template<typename C>
constexpr auto&& invoke(auto C::* f, auto&& arg)
requires (
!same_or_derived_from<decltype(arg), C>
&& requires { (*arg).*f; }
)
{
return (*std::forward<decltype(arg)>(arg)).*f;
}
template<typename C, typename... Args>
constexpr auto invoke(is_func auto C::* f, same_or_derived_from<C> auto&& self, Args&&... args)
-> decltype((std::forward<decltype(self)>(self).*f)(std::forward<Args>(args)...))
requires requires { (self.*f)(std::forward<Args>(args)...); }
{
return (std::forward<decltype(self)>(self).*f)(std::forward<Args>(args)...);
}
template<typename... Args, typename C>
constexpr auto invoke(is_func auto C::* f, auto* self, Args&&... args)
-> decltype((self->*f)(std::forward<Args>(args)...))
requires requires {
(self->*f)(std::forward<Args>(args)...);
}
{
return (self->*f)(std::forward<Args>(args)...);
}
template<typename... Args, typename C>
constexpr auto invoke(is_object auto C::* m, auto&& self, Args&&...)
-> decltype(self.*m)
template<typename C, typename... Args>
constexpr auto invoke(is_func auto C::* f, auto&& self, Args&&... args)
-> decltype(((*std::forward<decltype(self)>(self)).*f)(std::forward<Args>(args)...))
requires (
sizeof...(Args) == 0 &&
requires { self.*m; }
!same_or_derived_from<decltype(self), C>
&& requires { ((*self).*f)(std::forward<Args>(args)...); }
)
{
return std::forward<decltype(self)>(self).*m;
}
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; }
)
{
return self->*m;
}
template<typename... Args>
constexpr auto invoke(auto&& f, Args&&... args)
-> decltype(f(std::forward<Args>(args)...))
requires requires {
f(std::forward<Args>(args)...);
}
{
return std::forward<decltype(f)>(f)(std::forward<Args>(args)...);
return ((*std::forward<decltype(self)>(self)).*f)(std::forward<Args>(args)...);
}
template<typename Void, typename F, typename... Args>

View File

@ -7,9 +7,12 @@
struct HasFunction
{
void do_something(int, float) {}
void do_something(int, float) const {}
int& do_something2(int, float) &;
};
struct HasFunction2 : public HasFunction {};
struct HasMember
{
int member{};
@ -17,6 +20,8 @@ struct HasMember
void (*member_fn)(){};
};
struct HasMember2 : public HasMember {};
struct Functor
{
int64_t operator()() { return 35; }
@ -34,7 +39,13 @@ 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::same_as<asl::invoke_result_t<decltype(&HasFunction::do_something), const HasFunction2&, int, float>, void>);
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(&HasFunction::do_something2), HasFunction2&, int, float>, int&>);
static_assert(asl::same_as<asl::invoke_result_t<decltype(&HasFunction::do_something2), HasFunction*, int, float>, int&>);
static_assert(asl::same_as<asl::invoke_result_t<decltype(&HasMember::member), HasMember>, int&&>);
static_assert(asl::same_as<asl::invoke_result_t<decltype(&HasMember::member), const HasMember&>, const int&>);
static_assert(asl::same_as<asl::invoke_result_t<decltype(&HasMember::member), const HasMember2*>, const int&>);
static_assert(asl::invocable<int()>);
static_assert(!asl::invocable<int(), int>);
@ -45,8 +56,17 @@ 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), const HasFunction2&, int, 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>);
static_assert(!asl::invocable<decltype(&HasFunction::do_something2), HasFunction, int, float>);
static_assert(!asl::invocable<decltype(&HasFunction::do_something2), const HasFunction2&, int, float>);
static_assert(asl::invocable<decltype(&HasFunction::do_something2), HasFunction2&, int, float>);
static_assert(asl::invocable<decltype(&HasFunction::do_something2), HasFunction*, int, float>);
static_assert(!asl::invocable<decltype(&HasFunction::do_something2), HasFunction, int, int*>);
static_assert(asl::invocable<decltype(&HasMember::member), const HasMember2>);
static_assert(asl::invocable<decltype(&HasMember::member), const HasMember&>);
static_assert(asl::invocable<decltype(&HasMember::member), const HasMember2*>);
ASL_TEST(invoke_member_function)
{

View File

@ -92,12 +92,6 @@ template<typename T> concept trivially_destructible = __is_trivially_destructibl
template<typename T> concept copyable = copy_constructible<T> && copy_assignable<T>;
template<typename T> concept moveable = move_constructible<T> && move_assignable<T>;
template<typename From, typename To>
concept convertible_to = __is_convertible(From, To);
template<typename Derived, class Base>
concept derived_from = __is_class(Derived) && __is_class(Base) && convertible_to<const volatile Derived*, const volatile Base*>;
using nullptr_t = decltype(nullptr);
template<typename T> struct _un_const_helper { using type = T; };
@ -154,6 +148,15 @@ template<typename T> struct _is_ptr_helper<T*> : true_type {};
template<typename T> concept is_ptr = _is_ptr_helper<un_cv_t<T>>::value;
template<typename From, typename To>
concept convertible_to = __is_convertible(From, To);
template<typename Derived, typename Base>
concept derived_from = __is_class(Derived) && __is_class(Base) && convertible_to<const volatile Derived*, const volatile Base*>;
template<typename Derived, typename Base>
concept same_or_derived_from = same_as<un_cvref_t<Derived>, Base> || derived_from<un_cvref_t<Derived>, Base>;
template<typename T> struct _tame_helper { using type = T; };
#define TAME_HELPER_IMPL(TRAILING) \

View File

@ -168,6 +168,8 @@ static_assert(!asl::is_member_func_ptr<void()>);
static_assert(!asl::is_member_func_ptr<void() const &&>);
static_assert(!asl::is_member_func_ptr<int MyClass::*>);
static_assert(asl::is_member_func_ptr<int (MyClass::*)(int)>);
static_assert(asl::is_member_func_ptr<int (MyClass::*)(int) const>);
static_assert(asl::is_member_func_ptr<int (MyClass::*)(int) volatile &&>);
static_assert(asl::same_as<int, asl::tame_t<int>>);
static_assert(asl::same_as<int(), asl::tame_t<int()>>);
@ -250,6 +252,8 @@ static_assert(!asl::convertible_to<const int16_t(&)[], int16_t(&)[]>);
static_assert(!asl::convertible_to<D(&)[], C(&)[]>);
static_assert(asl::derived_from<Derived, Base>);
static_assert(asl::derived_from<Derived, Derived>);
static_assert(asl::derived_from<Base, Base>);
static_assert(!asl::derived_from<Base, Derived>);
static_assert(!asl::derived_from<D, C>);
static_assert(!asl::derived_from<C, D>);
@ -257,6 +261,16 @@ static_assert(!asl::derived_from<uint8_t, uint16_t>);
static_assert(!asl::derived_from<uint16_t, uint8_t>);
static_assert(!asl::derived_from<int, int>);
static_assert(asl::same_or_derived_from<Derived, Base>);
static_assert(asl::same_or_derived_from<Derived, Derived>);
static_assert(asl::same_or_derived_from<Base, Base>);
static_assert(!asl::same_or_derived_from<Base, Derived>);
static_assert(!asl::same_or_derived_from<D, C>);
static_assert(!asl::same_or_derived_from<C, D>);
static_assert(!asl::same_or_derived_from<uint8_t, uint16_t>);
static_assert(!asl::same_or_derived_from<uint16_t, uint8_t>);
static_assert(asl::same_or_derived_from<int, int>);
static_assert(!asl::is_const<int>);
static_assert(asl::is_const<const int>);
static_assert(!asl::is_const<const int*>);

View File

@ -1 +1,2 @@
Separate memory and allocator
Add invoke_t & co