Explorar el Código

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

Michele Caini hace 7 años
padre
commit
3c9a6ad218
Se han modificado 4 ficheros con 30 adiciones y 13 borrados
  1. 2 3
      TODO
  2. 9 5
      docs/signal.md
  3. 2 2
      src/entt/signal/delegate.hpp
  4. 17 3
      test/entt/signal/delegate.cpp

+ 2 - 3
TODO

@@ -22,7 +22,6 @@
 * tags revenge: if it's possible, reintroduce them but without a link to entities (see #169 for more details)
 * tags revenge: if it's possible, reintroduce them but without a link to entities (see #169 for more details)
 
 
 Ready to go:
 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!
 * (even more) optimized standard views are possible!
-* induce-respect policy
+* add on-the-fly sort functionality
+* introduce induce-respect policy

+ 9 - 5
docs/signal.md

@@ -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
 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
 implemented internally (that is something that goes beyond the purposes of this
 document).<br/>
 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:
 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`.
 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
 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
 # Event dispatcher
 
 

+ 2 - 2
src/entt/signal/delegate.hpp

@@ -159,11 +159,11 @@ public:
         static_assert(sizeof(Type) <= sizeof(void *));
         static_assert(sizeof(Type) <= sizeof(void *));
         static_assert(std::is_trivially_copyable_v<Type>);
         static_assert(std::is_trivially_copyable_v<Type>);
         static_assert(std::is_trivially_destructible_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};
         new (&storage) Type{value_or_instance};
 
 
         fn = [](storage_type &storage, Args... args) -> Ret {
         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...);
             return std::invoke(Candidate, value_or_instance, args...);
         };
         };
     }
     }

+ 17 - 3
test/entt/signal/delegate.cpp

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