delegate: curried functions can accept linked parameters either by value or by reference

This commit is contained in:
Michele Caini
2019-01-01 15:01:13 +01:00
parent f0389d6b47
commit 3c9a6ad218
4 changed files with 30 additions and 13 deletions

5
TODO
View File

@@ -22,7 +22,6 @@
* tags revenge: if it's possible, reintroduce them but without a link to entities (see #169 for more details)
Ready to go:
==> req: ref to value with curried functions
* add on-the-fly sort functionality (is it possible?)
* (even more) optimized standard views are possible!
* induce-respect policy
* add on-the-fly sort functionality
* introduce induce-respect policy

View File

@@ -229,10 +229,10 @@ As shown previously, it accepts functions having type `void(int)`. However, we
can do something more in this case, because of how the delegate class is
implemented internally (that is something that goes beyond the purposes of this
document).<br/>
In particular, the delegate accepts also functions having type `void(T, int)`,
as long as `sizeof(T)` is lower than or equal to `sizeof(void *)`. The first
parameter is stored directly by the delegate class and passed to the connected
function when needed.
In particular, the delegate accepts also functions having type equivalent to
`void(T &, int)`, as long as `sizeof(T)` is lower than or equal to
`sizeof(void *)`. The first parameter is stored directly by the delegate class
and passed to the connected function when needed.
In other terms, this works as well with the above definition:
@@ -245,7 +245,11 @@ delegate(42);
In this case, the function `g` is invoked with parameters `'c'` and `42`.
However, the function type of the delegate is still `void(int)`, mainly because
this is also the signature of its function call operator.
this is also the signature of its function call operator.<br/>
When the curried function gets the linked parameter by reference, it can modify
it and the new value will be stored in place of the previous one. It's highly
discouraged to accept the parameter by reference, unless you know exactly what
you're doing. Prefer accepting it by value if possible.
# Event dispatcher

View File

@@ -159,11 +159,11 @@ public:
static_assert(sizeof(Type) <= sizeof(void *));
static_assert(std::is_trivially_copyable_v<Type>);
static_assert(std::is_trivially_destructible_v<Type>);
static_assert(std::is_invocable_r_v<Ret, decltype(Candidate), Type, Args...>);
static_assert(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>);
new (&storage) Type{value_or_instance};
fn = [](storage_type &storage, Args... args) -> Ret {
Type value_or_instance = *reinterpret_cast<Type *>(&storage);
Type &value_or_instance = *reinterpret_cast<Type *>(&storage);
return std::invoke(Candidate, value_or_instance, args...);
};
}

View File

@@ -5,10 +5,15 @@ int delegate_function(const int &i) {
return i*i;
}
int curried_function(int i, int j) {
int curried_function_by_value(int i, int j) {
return i+j;
}
int curried_function_by_ref(int &value) {
value *= 2;
return value;
}
struct delegate_functor {
int operator()(int i) {
return i+i;
@@ -194,10 +199,19 @@ TEST(Delegate, ConstInstance) {
ASSERT_EQ(delegate, entt::delegate<int(int)>{});
}
TEST(Delegate, CurriedFunction) {
TEST(Delegate, CurriedFunctionByValue) {
entt::delegate<int(int)> delegate;
delegate.connect<&curried_function>(3);
delegate.connect<&curried_function_by_value>(3);
ASSERT_TRUE(delegate);
ASSERT_EQ(delegate(1), 4);
}
TEST(Delegate, CurriedFunctionByRef) {
entt::delegate<int()> delegate;
delegate.connect<&curried_function_by_ref>(2);
ASSERT_TRUE(delegate);
ASSERT_EQ(delegate(), 4);
ASSERT_EQ(delegate(), 8);
}