Add function with invoke and result_of_t
This commit is contained in:
@ -5,6 +5,7 @@ cc_library(
|
|||||||
"assert.hpp",
|
"assert.hpp",
|
||||||
"config.hpp",
|
"config.hpp",
|
||||||
"format.hpp",
|
"format.hpp",
|
||||||
|
"functional.hpp",
|
||||||
"integers.hpp",
|
"integers.hpp",
|
||||||
"io.hpp",
|
"io.hpp",
|
||||||
"layout.hpp",
|
"layout.hpp",
|
||||||
@ -34,6 +35,7 @@ cc_library(
|
|||||||
],
|
],
|
||||||
) for name in [
|
) for name in [
|
||||||
"format",
|
"format",
|
||||||
|
"functional",
|
||||||
"integers",
|
"integers",
|
||||||
"maybe_uninit",
|
"maybe_uninit",
|
||||||
"meta",
|
"meta",
|
||||||
|
65
asl/functional.hpp
Normal file
65
asl/functional.hpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "asl/meta.hpp"
|
||||||
|
#include "asl/utility.hpp"
|
||||||
|
|
||||||
|
namespace asl {
|
||||||
|
|
||||||
|
template<typename... Args, typename C>
|
||||||
|
constexpr auto invoke(is_func auto C::* f, auto&& self, Args&&... args)
|
||||||
|
requires requires {
|
||||||
|
(self.*f)(ASL_FWD(args)...);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
return (ASL_FWD(self).*f)(ASL_FWD(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args, typename C>
|
||||||
|
constexpr auto invoke(is_func auto C::* f, auto* self, Args&&... args)
|
||||||
|
requires requires {
|
||||||
|
(self->*f)(ASL_FWD(args)...);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
return (self->*f)(ASL_FWD(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args, typename C>
|
||||||
|
constexpr auto invoke(is_object auto C::* m, auto&& self, Args&&...)
|
||||||
|
requires (
|
||||||
|
sizeof...(Args) == 0 &&
|
||||||
|
requires { self.*m; }
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return ASL_FWD(self).*m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args, typename C>
|
||||||
|
constexpr auto invoke(is_object auto C::* m, auto* self, Args&&...)
|
||||||
|
requires (
|
||||||
|
sizeof...(Args) == 0 &&
|
||||||
|
requires { self->*m; }
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return self->*m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
constexpr auto invoke(auto&& f, Args&&... args)
|
||||||
|
requires requires {
|
||||||
|
f(ASL_FWD(args)...);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
return ASL_FWD(f)(ASL_FWD(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F> struct _result_of_helper;
|
||||||
|
|
||||||
|
template<typename R, typename... Args>
|
||||||
|
struct _result_of_helper<R(Args...)>
|
||||||
|
{
|
||||||
|
using type = decltype(invoke(declval<R>(), declval<Args>()...));
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename F> using result_of_t = _result_of_helper<F>::type;
|
||||||
|
|
||||||
|
} // namespace asl
|
@ -35,6 +35,8 @@ template<typename T> auto _as_rref_helper(...) -> id<T>;
|
|||||||
template<typename T> using as_lref_t = decltype(_as_lref_helper<T>(0))::type;
|
template<typename T> using as_lref_t = decltype(_as_lref_helper<T>(0))::type;
|
||||||
template<typename T> using as_rref_t = decltype(_as_rref_helper<T>(0))::type;
|
template<typename T> using as_rref_t = decltype(_as_rref_helper<T>(0))::type;
|
||||||
|
|
||||||
|
template<typename T> consteval as_rref_t<T> declval() {}
|
||||||
|
|
||||||
template<typename T> struct _un_ref_t { using type = T; };
|
template<typename T> struct _un_ref_t { using type = T; };
|
||||||
template<typename T> struct _un_ref_t<T&> { using type = T; };
|
template<typename T> struct _un_ref_t<T&> { using type = T; };
|
||||||
template<typename T> struct _un_ref_t<T&&> { using type = T; };
|
template<typename T> struct _un_ref_t<T&&> { using type = T; };
|
||||||
@ -67,9 +69,13 @@ template<typename T> concept trivially_destructible = __is_trivially_destructibl
|
|||||||
|
|
||||||
template<typename T> concept trivially_copyable = __is_trivially_copyable(T);
|
template<typename T> concept trivially_copyable = __is_trivially_copyable(T);
|
||||||
|
|
||||||
|
// @Todo Rename concepts (_from)
|
||||||
template<typename From, typename To>
|
template<typename From, typename To>
|
||||||
concept convertible = __is_convertible(From, To);
|
concept convertible = __is_convertible(From, To);
|
||||||
|
|
||||||
|
template<typename Derived, class Base>
|
||||||
|
concept derived_from = __is_class(Derived) && __is_class(Base) && convertible<const volatile Derived*, const volatile Base*>;
|
||||||
|
|
||||||
using nullptr_t = decltype(nullptr);
|
using nullptr_t = decltype(nullptr);
|
||||||
|
|
||||||
template<typename T> struct _un_const_helper { using type = T; };
|
template<typename T> struct _un_const_helper { using type = T; };
|
||||||
|
73
asl/tests/functional_tests.cpp
Normal file
73
asl/tests/functional_tests.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#include "asl/functional.hpp"
|
||||||
|
#include "asl/testing/testing.hpp"
|
||||||
|
|
||||||
|
struct HasFunction
|
||||||
|
{
|
||||||
|
void do_something(int, float) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HasMember
|
||||||
|
{
|
||||||
|
int member{};
|
||||||
|
int member_array[4]{};
|
||||||
|
void (*member_fn)(){};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Functor
|
||||||
|
{
|
||||||
|
int64_t operator()() { return 35; }
|
||||||
|
int operator()(int x) { return x; }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int some_func0() { return 1; }
|
||||||
|
static int some_func1(int x) { return x + 1; }
|
||||||
|
static float some_func1(float x) { return x + 1; }
|
||||||
|
static int some_func2(int x, int b) { return x + b; }
|
||||||
|
|
||||||
|
static_assert(asl::is_same<asl::result_of_t<Functor()>, int64_t>);
|
||||||
|
static_assert(asl::is_same<asl::result_of_t<Functor(int)>, int>);
|
||||||
|
static_assert(asl::is_same<asl::result_of_t<decltype(static_cast<float(*)(float)>(some_func1))(float)>, float>);
|
||||||
|
static_assert(asl::is_same<asl::result_of_t<decltype(&HasFunction::do_something)(HasFunction, int, float)>, void>);
|
||||||
|
static_assert(asl::is_same<asl::result_of_t<decltype(&HasMember::member)(HasMember)>, int>);
|
||||||
|
|
||||||
|
ASL_TEST(invoke_member_function)
|
||||||
|
{
|
||||||
|
HasFunction c;
|
||||||
|
asl::invoke(&HasFunction::do_something, c, 5, 5.0F);
|
||||||
|
asl::invoke(&HasFunction::do_something, &c, 5, 5.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASL_TEST(invoke_member_data)
|
||||||
|
{
|
||||||
|
HasMember c;
|
||||||
|
|
||||||
|
asl::invoke(&HasMember::member, c);
|
||||||
|
asl::invoke(&HasMember::member_array, c);
|
||||||
|
asl::invoke(&HasMember::member_fn, c);
|
||||||
|
asl::invoke(&HasMember::member, &c);
|
||||||
|
asl::invoke(&HasMember::member_array, &c);
|
||||||
|
asl::invoke(&HasMember::member_fn, &c);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASL_TEST(invoke_fn)
|
||||||
|
{
|
||||||
|
ASL_TEST_EXPECT(asl::invoke(some_func0) == 1);
|
||||||
|
ASL_TEST_EXPECT(asl::invoke(static_cast<int(*)(int)>(some_func1), 8) == 9);
|
||||||
|
ASL_TEST_EXPECT(asl::invoke(some_func2, 4, 8) == 12);
|
||||||
|
ASL_TEST_EXPECT(asl::invoke(&some_func0) == 1);
|
||||||
|
ASL_TEST_EXPECT(asl::invoke(static_cast<int(*)(int)>(&some_func1), 8) == 9);
|
||||||
|
ASL_TEST_EXPECT(asl::invoke(&some_func2, 4, 8) == 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASL_TEST(invoke_operator_call)
|
||||||
|
{
|
||||||
|
Functor f;
|
||||||
|
ASL_TEST_EXPECT(asl::invoke(f) == 35);
|
||||||
|
ASL_TEST_EXPECT(asl::invoke(f, 8) == 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASL_TEST(invoke_lambda)
|
||||||
|
{
|
||||||
|
ASL_TEST_EXPECT(asl::invoke([](){ return 35; }) == 35);
|
||||||
|
ASL_TEST_EXPECT(asl::invoke([](int x){ return x + 2; }, 6) == 8);
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
#include "asl/tests/test_types.hpp"
|
#include "asl/tests/test_types.hpp"
|
||||||
|
#include "asl/testing/testing.hpp"
|
||||||
|
|
||||||
struct Struct {};
|
struct Struct {};
|
||||||
union Union {};
|
union Union {};
|
||||||
@ -180,3 +181,12 @@ static_assert(!asl::convertible<Base*, Derived*>);
|
|||||||
static_assert(asl::convertible<D, C>);
|
static_assert(asl::convertible<D, C>);
|
||||||
static_assert(!asl::convertible<Derived*, C*>);
|
static_assert(!asl::convertible<Derived*, C*>);
|
||||||
static_assert(asl::convertible<Base, E>);
|
static_assert(asl::convertible<Base, E>);
|
||||||
|
|
||||||
|
static_assert(asl::derived_from<Derived, Base>);
|
||||||
|
static_assert(!asl::derived_from<Base, Derived>);
|
||||||
|
static_assert(!asl::derived_from<D, C>);
|
||||||
|
static_assert(!asl::derived_from<C, D>);
|
||||||
|
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>);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user