refactor SignalBase and CallbackBase using variadic template. 94/245194/3
authorSubhransu Mohanty <sub.mohanty@samsung.com>
Mon, 5 Oct 2020 07:15:21 +0000 (16:15 +0900)
committerDavid Steele <david.steele@samsung.com>
Wed, 7 Oct 2020 11:48:56 +0000 (12:48 +0100)
Variadic template and parameter pack makes the Api list much shorter
and enables for future optimization.

Removed assertion from Callback::Execute if an empty callback has
been setup.

Fixed negative test case.

Change-Id: I11060630ef4b82fc9966610b5c63ef2fa27b3779

automated-tests/src/dali/utc-Dali-SignalTemplates.cpp
dali/public-api/signals/base-signal.cpp
dali/public-api/signals/base-signal.h
dali/public-api/signals/callback.h

index e612ccb..d3a03fc 100644 (file)
@@ -167,23 +167,16 @@ int UtcDaliSignalConnectP01(void)
 
 int UtcDaliSignalConnectN01(void)
 {
-  // difficult to perform a negative test on Connect as no checks are performed
-  // when creating a callback for a null function ( during Connect).
-  // so we test an assert on Emit
   TestApplication application; // Create core for debug logging
 
   TestSignals::VoidRetNoParamSignal signal;
-  signal.Connect(NULL);
-  try
-  {
-    signal.Emit();
-  }
-  catch(Dali::DaliException& e)
-  {
-    // Tests that a negative test of an assertion succeeds
-    DALI_TEST_PRINT_ASSERT(e);
-    tet_result(TET_PASS);
-  }
+  signal.Connect(nullptr);
+  signal.Emit();
+
+  // No assert occurs any more - the callback is silently ignored.
+  // If we execute this code, then the test case didn't crash.
+  tet_result(TET_PASS);
+
   END_TEST;
 }
 
index e36ae74..eb52b56 100644 (file)
@@ -60,35 +60,6 @@ BaseSignal::~BaseSignal()
   }
 }
 
-void BaseSignal::Emit()
-{
-  // Guards against nested Emit() calls
-  EmitGuard guard(mEmittingFlag); // Guards against nested Emit() calls
-  if(guard.ErrorOccurred())
-  {
-    return;
-  }
-
-  // If more connections are added by callbacks, these are ignore until the next Emit()
-  // Note that mSignalConnections.Count() count cannot be reduced while iterating
-  const std::size_t initialCount(mSignalConnections.size());
-
-  for(std::size_t i = 0; i < initialCount; ++i)
-  {
-    CallbackBase* callback(GetCallback(i));
-
-    // Note that connections will be set to NULL when disconnected
-    // This is preferable to reducing the connection count while iterating
-    if(callback)
-    {
-      CallbackBase::Execute(*callback);
-    }
-  }
-
-  // Cleanup NULL values from Connection container
-  CleanupConnections();
-}
-
 void BaseSignal::OnConnect(CallbackBase* callback)
 {
   DALI_ASSERT_ALWAYS(nullptr != callback && "Invalid member function pointer passed to Connect()");
index 359a5f3..63dc801 100644 (file)
@@ -150,22 +150,15 @@ public:
   };
 
   /**
-   * @brief Emits a signal with no parameters.
+   * @brief Emits a signal with parameter pack.
    *
-   * @SINCE_1_0.0
-   * @pre Cannot be called from inside the same Signal's Emit methods.
-   */
-  void Emit();
-
-  /**
-   * @brief Emits a signal with no parameters.
-   *
-   * @SINCE_1_0.0
+   * @SINCE_1_9.33
+   * @param[in] args The parameter pack
    * @return The value returned by the last callback
    * @pre Cannot be called from inside the same Signal's Emit methods.
    */
-  template<typename Ret>
-  Ret EmitReturn()
+  template<typename Ret, typename... Args>
+  Ret EmitReturn(Args... args)
   {
     Ret returnVal = Ret();
 
@@ -188,86 +181,7 @@ public:
       // This is preferable to reducing the connection count while iterating
       if(callback)
       {
-        returnVal = CallbackBase::ExecuteReturn<Ret>(*callback);
-      }
-    }
-
-    // Cleanup NULL values from Connection container
-    CleanupConnections();
-
-    return returnVal;
-  }
-
-  /**
-   * @brief Emits a signal with 1 parameter.
-   *
-   * @SINCE_1_0.0
-   * @param[in] arg0 The first parameter
-   * @pre Cannot be called from inside the same Signal's Emit methods.
-   */
-  template<typename Arg0>
-  void Emit(Arg0 arg0)
-  {
-    // Guards against nested Emit() calls
-    EmitGuard guard(mEmittingFlag); // Guards against nested Emit() calls
-    if(guard.ErrorOccurred())
-    {
-      return;
-    }
-
-    // If more connections are added by callbacks, these are ignore until the next Emit()
-    // Note that count cannot be reduced while iterating
-    const std::size_t initialCount(mSignalConnections.size());
-
-    for(std::size_t i = 0; i < initialCount; ++i)
-    {
-      CallbackBase* callback(GetCallback(i));
-
-      // Note that connections will be set to NULL when disconnected
-      // This is preferable to reducing the connection count while iterating
-      if(callback)
-      {
-        CallbackBase::Execute<Arg0>(*callback, arg0);
-      }
-    }
-
-    // Cleanup NULL values from Connection container
-    CleanupConnections();
-  }
-
-  /**
-   * @brief Emits a signal with 1 parameter.
-   *
-   * @SINCE_1_0.0
-   * @param[in] arg0 The first parameter
-   * @return The value returned by the last callback
-   * @pre Cannot be called from inside the same Signal's Emit methods.
-   */
-  template<typename Ret, typename Arg0>
-  Ret EmitReturn(Arg0 arg0)
-  {
-    Ret returnVal = Ret();
-
-    // Guards against nested Emit() calls
-    EmitGuard guard(mEmittingFlag); // Guards against nested Emit() calls
-    if(guard.ErrorOccurred())
-    {
-      return returnVal;
-    }
-
-    // If more connections are added by callbacks, these are ignore until the next Emit()
-    // Note that count cannot be reduced while iterating
-    const std::size_t initialCount(mSignalConnections.size());
-
-    for(std::size_t i = 0; i < initialCount; ++i)
-    {
-      CallbackBase* callback(GetCallback(i));
-
-      // Note that connections will be set to NULL when disconnected
-      // This is preferable to reducing the connection count while iterating
-      if(callback)
-      {
-        returnVal = CallbackBase::ExecuteReturn<Ret, Arg0>(*callback, arg0);
+        returnVal = CallbackBase::ExecuteReturn<Ret, Args...>(*callback, args...);
       }
     }
 
@@ -278,15 +192,14 @@ public:
   }
 
   /**
-   * @brief Emits a signal with 2 parameters.
+   * @brief Emits a signal with  parameter pack.
    *
-   * @SINCE_1_0.0
-   * @param[in] arg0 The first parameter
-   * @param[in] arg1 The second parameter
+   * @SINCE_1_9.33
+   * @param[in] args The parameter pack
    * @pre Cannot be called from inside the same Signal's Emit methods.
    */
-  template<typename Arg0, typename Arg1>
-  void Emit(Arg0 arg0, Arg1 arg1)
+  template<typename... Args>
+  void Emit(Args... args)
   {
     // Guards against nested Emit() calls
     EmitGuard guard(mEmittingFlag); // Guards against nested Emit() calls
@@ -307,7 +220,7 @@ public:
       // This is preferable to reducing the connection count while iterating
       if(callback)
       {
-        CallbackBase::Execute<Arg0, Arg1>(*callback, arg0, arg1);
+        CallbackBase::Execute<Args...>(*callback, args...);
       }
     }
 
@@ -315,132 +228,6 @@ public:
     CleanupConnections();
   }
 
-  /**
-   * @brief Emits a signal with 2 parameters.
-   *
-   * @SINCE_1_0.0
-   * @param[in] arg0 The first parameter
-   * @param[in] arg1 The second parameter
-   * @return The value returned by the last callback
-   * @pre Cannot be called from inside the same Signal's Emit methods.
-   */
-  template<typename Ret, typename Arg0, typename Arg1>
-  Ret EmitReturn(Arg0 arg0, Arg1 arg1)
-  {
-    Ret returnVal = Ret();
-
-    // Guards against nested Emit() calls
-    EmitGuard guard(mEmittingFlag); // Guards against nested Emit() calls
-    if(guard.ErrorOccurred())
-    {
-      return returnVal;
-    }
-
-    // If more connections are added by callbacks, these are ignore until the next Emit()
-    // Note that count cannot be reduced while iterating
-    const std::size_t initialCount(mSignalConnections.size());
-
-    for(std::size_t i = 0; i < initialCount; ++i)
-    {
-      CallbackBase* callback(GetCallback(i));
-
-      // Note that connections will be set to NULL when disconnected
-      // This is preferable to reducing the connection count while iterating
-      if(callback)
-      {
-        returnVal = CallbackBase::ExecuteReturn<Ret, Arg0, Arg1>(*callback, arg0, arg1);
-      }
-    }
-
-    // Cleanup NULL values from Connection container
-    CleanupConnections();
-
-    return returnVal;
-  }
-
-  /**
-   * @brief Emits a signal with 3 parameters.
-   *
-   * @SINCE_1_0.0
-   * @param[in] arg0 The first parameter
-   * @param[in] arg1 The second parameter
-   * @param[in] arg2 The third parameter
-   * @pre Cannot be called from inside the same Signal's Emit methods.
-   */
-  template<typename Arg0, typename Arg1, typename Arg2>
-  void Emit(Arg0 arg0, Arg1 arg1, Arg2 arg2)
-  {
-    // Guards against nested Emit() calls
-    EmitGuard guard(mEmittingFlag); // Guards against nested Emit() calls
-    if(guard.ErrorOccurred())
-    {
-      return;
-    }
-
-    // If more connections are added by callbacks, these are ignore until the next Emit()
-    // Note that count cannot be reduced while iterating
-    const std::size_t initialCount(mSignalConnections.size());
-
-    for(std::size_t i = 0; i < initialCount; ++i)
-    {
-      CallbackBase* callback(GetCallback(i));
-
-      // Note that connections will be set to NULL when disconnected
-      // This is preferable to reducing the connection count while iterating
-      if(callback)
-      {
-        CallbackBase::Execute<Arg0, Arg1, Arg2>(*callback, arg0, arg1, arg2);
-      }
-    }
-
-    // Cleanup NULL values from Connection container
-    CleanupConnections();
-  }
-
-  /**
-   * @brief Emits a signal with 3 parameters.
-   *
-   * @SINCE_1_0.0
-   * @param[in] arg0 The first parameter
-   * @param[in] arg1 The second parameter
-   * @param[in] arg2 The third parameter
-   * @return The value returned by the last callback
-   * @pre Cannot be called from inside the same Signal's Emit methods.
-   */
-  template<typename Ret, typename Arg0, typename Arg1, typename Arg2>
-  Ret EmitReturn(Arg0 arg0, Arg1 arg1, Arg2 arg2)
-  {
-    Ret returnVal = Ret();
-
-    // Guards against nested Emit() calls
-    EmitGuard guard(mEmittingFlag); // Guards against nested Emit() calls
-    if(guard.ErrorOccurred())
-    {
-      return returnVal;
-    }
-
-    // If more connections are added by callbacks, these are ignore until the next Emit()
-    // Note that count cannot be reduced while iterating
-    const std::size_t initialCount(mSignalConnections.size());
-
-    for(std::size_t i = 0; i < initialCount; ++i)
-    {
-      CallbackBase* callback(GetCallback(i));
-
-      // Note that connections will be set to NULL when disconnected
-      // This is preferable to reducing the connection count while iterating
-      if(callback)
-      {
-        returnVal = CallbackBase::ExecuteReturn<Ret, Arg0, Arg1, Arg2>(*callback, arg0, arg1, arg2);
-      }
-    }
-
-    // Cleanup NULL values from Connection container
-    CleanupConnections();
-
-    return returnVal;
-  }
-
   // Connect / Disconnect function for use by Signal implementations
 
   /**
index 5722811..0acc43d 100644 (file)
@@ -62,102 +62,14 @@ public:
   /**
    * @brief Function to call the function or member function dispatcher.
    *
-   * @SINCE_1_0.0
-   * @param[in] callback The callback to call
-   */
-  static void Execute(CallbackBase& callback)
-  {
-    // if we point to a function, we can call it directly
-    // otherwise call the dispatcher function that knows the real type of the object
-    // Note that this template dispatcher lives in client code so the library containing
-    // the code has to be loaded, otherwise we crash boom bang
-    if(callback.mImpl.mObjectPointer)
-    {
-      Dispatcher dispatcher = callback.mImpl.mMemberFunctionDispatcher;
-      (*dispatcher)(callback);
-    }
-    // its also possible to have a member function pointer to a CallbackProvider
-    // that has been deleted, so check if we have impl still
-    else if(callback.mFunction)
-    {
-      (*(callback.mFunction))();
-    }
-    else
-    {
-      DALI_ASSERT_ALWAYS(0 && "no function to execute");
-    }
-  }
-
-  /**
-   * @brief Function to call the function or member function dispatcher.
-   *
-   * @SINCE_1_0.0
-   * @param[in] callback The callback to call
-   * @return The value from the function
-   */
-  template<typename R>
-  static R ExecuteReturn(CallbackBase& callback)
-  {
-    R returnVal = R();
-    // if we point to a function, we can call it directly
-    // otherwise call the dispatcher function that knows the real type of the object
-    // Note that this template dispatcher lives in client code so the library containing
-    // the code has to be loaded, otherwise we crash boom bang
-    if(callback.mImpl.mObjectPointer)
-    {
-      using Dispatcher      = R (*)(CallbackBase&);
-      Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl.mMemberFunctionDispatcher);
-      returnVal             = (*dispatcher)(callback);
-    }
-    else if(callback.mFunction)
-    {
-      using Function1 = R (*)();
-      returnVal       = (*(reinterpret_cast<Function1>(callback.mFunction)))();
-    }
-
-    return returnVal;
-  }
-
-  /**
-   * @brief Function to call the function or member function dispatcher.
-   *
    * This function template gets instantiated at the call site.
-   * @SINCE_1_0.0
+   * @SINCE_1_9.33
    * @param[in] callback The callback to call
-   * @param[in] param1 The first parameter to pass into the function
-   */
-  template<typename P1>
-  static void Execute(CallbackBase& callback, P1 param1)
-  {
-    // if we point to a function, we can call it directly
-    // otherwise call the dispatcher function that knows the real type of the object
-    // Note that this template dispatcher lives in client code (where the callback was created)
-    // so the library containing the code has to be loaded, otherwise we crash boom bang
-    if(callback.mImpl.mObjectPointer)
-    {
-      using Dispatcher      = void (*)(CallbackBase&, P1);
-      Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl.mMemberFunctionDispatcher);
-      (*dispatcher)(callback, param1);
-    }
-    else if(callback.mFunction)
-    {
-      // convert function type
-      using Function1 = void (*)(P1);
-      (*(reinterpret_cast<Function1>(callback.mFunction)))(param1);
-    }
-  }
-
-  /**
-   * @brief Function to call the function or member function dispatcher.
-   *
-   * This function template gets instantiated at the call site.
-   * @SINCE_1_0.0
-   * @param[in] callback The callback to call
-   * @param[in] param1 The first parameter to pass into the function
+   * @param[in] args parameter pack to pass into the function
    * @return The value from the function
    */
-  template<typename R, typename P1>
-  static R ExecuteReturn(CallbackBase& callback, P1 param1)
+  template<typename R, typename... Args>
+  static R ExecuteReturn(CallbackBase& callback, Args... args)
   {
     R returnVal = R();
     // if we point to a function, we can call it directly
@@ -166,15 +78,15 @@ public:
     // so the library containing the code has to be loaded, otherwise we crash boom bang
     if(callback.mImpl.mObjectPointer)
     {
-      using Dispatcher      = R (*)(CallbackBase&, P1);
+      using Dispatcher      = R (*)(CallbackBase&, Args...);
       Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl.mMemberFunctionDispatcher);
-      returnVal             = (*dispatcher)(callback, param1);
+      returnVal             = (*dispatcher)(callback, args...);
     }
     else if(callback.mFunction)
     {
       // convert function type
-      using Function1 = R (*)(P1);
-      returnVal       = (*(reinterpret_cast<Function1>(callback.mFunction)))(param1);
+      using Function = R (*)(Args...);
+      returnVal       = (*(reinterpret_cast<Function>(callback.mFunction)))(args...);
     }
 
     return returnVal;
@@ -184,13 +96,12 @@ public:
    * @brief Function to call the function or member function dispatcher.
    *
    * This function template gets instantiated at the call site.
-   * @SINCE_1_0.0
+   * @SINCE_1_9.33
    * @param[in] callback The callback to call
-   * @param[in] param1 The first parameter to pass into the function
-   * @param[in] param2 The second parameter to pass into the function
+   * @param[in] args parameter pack to pass into the function
    */
-  template<typename P1, typename P2>
-  static void Execute(CallbackBase& callback, P1 param1, P2 param2)
+  template<typename... Args>
+  static void Execute(CallbackBase& callback, Args... args)
   {
     // if we point to a function, we can call it directly
     // otherwise call the dispatcher function that knows the real type of the object
@@ -198,124 +109,35 @@ public:
     // so the library containing the code has to be loaded, otherwise we crash boom bang
     if(callback.mImpl.mObjectPointer)
     {
-      using Dispatcher      = void (*)(CallbackBase&, P1, P2);
+      using Dispatcher      = void (*)(CallbackBase&, Args...);
       Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl.mMemberFunctionDispatcher);
-      (*dispatcher)(callback, param1, param2);
+      (*dispatcher)(callback, args...);
     }
     else if(callback.mFunction)
     {
       // convert function type
-      using Function2 = void (*)(P1, P2);
-      (*(reinterpret_cast<Function2>(callback.mFunction)))(param1, param2);
+      using Function = void (*)(Args...);
+      (*(reinterpret_cast<Function>(callback.mFunction)))(args...);
     }
   }
 
+public:
   /**
-   * @brief Function to call the function or member function dispatcher.
-   *
-   * This function template gets instantiated at the call site.
-   * @SINCE_1_0.0
-   * @param[in] callback The callback to call
-   * @param[in] param1 The first parameter to pass into the function
-   * @param[in] param2 The second parameter to pass into the function
-   * @return The return value from the function
-   */
-  template<typename R, typename P1, typename P2>
-  static R ExecuteReturn(CallbackBase& callback, P1 param1, P2 param2)
-  {
-    R returnVal = R();
-    // if we point to a function, we can call it directly
-    // otherwise call the dispatcher function that knows the real type of the object
-    // Note that this template dispatcher lives in client code (where the callback was created)
-    // so the library containing the code has to be loaded, otherwise we crash boom bang
-    if(callback.mImpl.mObjectPointer)
-    {
-      using Dispatcher      = R (*)(CallbackBase&, P1, P2);
-      Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl.mMemberFunctionDispatcher);
-      returnVal             = (*dispatcher)(callback, param1, param2);
-    }
-    else if(callback.mFunction)
-    {
-      // convert function type
-      using Function2 = R (*)(P1, P2);
-      returnVal       = (*(reinterpret_cast<Function2>(callback.mFunction)))(param1, param2);
-    }
-
-    return returnVal;
-  }
-
-  /**
-   * @brief Function to call the function or member function dispatcher.
-   *
-   * This function template gets instantiated at the call site.
+   * @brief Function with static linkage.
    * @SINCE_1_0.0
-   * @param[in] callback The callback to call
-   * @param[in] param1 The first parameter to pass into the function
-   * @param[in] param2 The second parameter to pass into the function
-   * @param[in] param3 The third parameter to pass into the function
    */
-  template<typename P1, typename P2, typename P3>
-  static void Execute(CallbackBase& callback, P1 param1, P2 param2, P3 param3)
-  {
-    // if we point to a function, we can call it directly
-    // otherwise call the dispatcher function that knows the real type of the object
-    // Note that this template dispatcher lives in client code (where the callback was created)
-    // so the library containing the code has to be loaded, otherwise we crash boom bang
-    if(callback.mImpl.mObjectPointer)
-    {
-      using Dispatcher      = void (*)(CallbackBase&, P1, P2, P3);
-      Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl.mMemberFunctionDispatcher);
-      (*dispatcher)(callback, param1, param2, param3);
-    }
-    else if(callback.mFunction)
-    {
-      // convert function type
-      using Function2 = void (*)(P1, P2, P3);
-      (*(reinterpret_cast<Function2>(callback.mFunction)))(param1, param2, param3);
-    }
-  }
+  using Function = void (*)();
 
   /**
-   * @brief Function to call the function or member function dispatcher.
+   * @brief Constructor for function with static linkage.
    *
-   * This function template gets instantiated at the call site.
    * @SINCE_1_0.0
-   * @param[in] callback The callback to call
-   * @param[in] param1 The first parameter to pass into the function
-   * @param[in] param2 The second parameter to pass into the function
-   * @param[in] param3 The third parameter to pass into the function
-   * @return The return value from the function
+   * @param[in] function The function to call
    */
-  template<typename R, typename P1, typename P2, typename P3>
-  static R ExecuteReturn(CallbackBase& callback, P1 param1, P2 param2, P3 param3)
-  {
-    R returnVal = R();
-    // if we point to a function, we can call it directly
-    // otherwise call the dispatcher function that knows the real type of the object
-    // Note that this template dispatcher lives in client code (where the callback was created)
-    // so the library containing the code has to be loaded, otherwise we crash boom bang
-    if(callback.mImpl.mObjectPointer)
-    {
-      using Dispatcher      = R (*)(CallbackBase&, P1, P2, P3);
-      Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl.mMemberFunctionDispatcher);
-      returnVal             = (*dispatcher)(callback, param1, param2, param3);
-    }
-    else if(callback.mFunction)
-    {
-      // convert function type
-      using Function2 = R (*)(P1, P2, P3);
-      returnVal       = (*(reinterpret_cast<Function2>(callback.mFunction)))(param1, param2, param3);
-    }
-
-    return returnVal;
-  }
+  CallbackBase(Function function);
 
 protected: // Constructors for deriving classes
-  /**
-   * @brief Function with static linkage.
-   * @SINCE_1_0.0
-   */
-  using Function = void (*)();
+
 
   /**
    * @brief Member function.
@@ -351,14 +173,6 @@ protected: // Constructors for deriving classes
   CallbackBase& operator=(const CallbackBase& rhs);
 
   /**
-   * @brief Constructor for function with static linkage.
-   *
-   * @SINCE_1_0.0
-   * @param[in] function The function to call
-   */
-  CallbackBase(Function function);
-
-  /**
    * @brief Constructor for member function.
    *
    * @SINCE_1_0.0
@@ -1126,69 +940,6 @@ public:
 };
 
 /**
- * @brief Specializations for static function callbacks.
- * @SINCE_1_0.0
- */
-class CallbackFunction : public CallbackBase
-{
-public:
-  /**
-   * @brief Default constructor.
-   * @SINCE_1_0.0
-   */
-  CallbackFunction()
-  : CallbackBase()
-  {
-  }
-
-  /**
-   * @brief Constructors for functions with static linkage.
-   *
-   * @SINCE_1_0.0
-   * @param[in] function The function to call
-   */
-  CallbackFunction(void (*function)())
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-  template<typename R>
-  CallbackFunction(R (*function)())
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-  template<typename P1>
-  CallbackFunction(void (*function)(P1))
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-  template<typename P1, typename R>
-  CallbackFunction(R (*function)(P1))
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-  template<typename P1, typename P2>
-  CallbackFunction(void (*function)(P1, P2))
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-  template<typename P1, typename P2, typename R>
-  CallbackFunction(R (*function)(P1, P2))
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-  template<typename P1, typename P2, typename P3>
-  CallbackFunction(void (*function)(P1, P2, P3))
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-  template<typename P1, typename P2, typename P3, typename R>
-  CallbackFunction(R (*function)(P1, P2, P3))
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-};
-
-/**
  * @brief Specializations for function object callbacks.
  * @SINCE_1_0.0
  */
@@ -1566,106 +1317,16 @@ public:
 // Callback creation thin templates
 
 /**
- * @brief Creates a callback from a C function or static member function with no parameters.
- *
- * @SINCE_1_0.0
- * @param[in] function The function to call
- * @return A newly allocated Callback object, ownership transferred to caller
- */
-inline CallbackBase* MakeCallback(void (*function)(void))
-{
-  return new CallbackFunction(function);
-}
-
-/**
- * @brief Creates a callback from a C function or static member function with one parameter.
- *
- * @SINCE_1_0.0
- * @param[in] function The function to call
- * @return A newly allocated Callback object, ownership transferred to caller
- */
-template<typename P1>
-inline CallbackBase* MakeCallback(void (*function)(P1))
-{
-  return new CallbackFunction(function);
-}
-
-/**
- * @brief Creates a callback from a C function or static member function with no parameters and a return type.
- *
- * @SINCE_1_0.0
- * @param[in] function The function to call
- * @return A newly allocated Callback object, ownership transferred to caller
- */
-template<typename R>
-inline CallbackBase* MakeCallback(R (*function)(void))
-{
-  return new CallbackFunction(function);
-}
-
-/**
- * @brief Creates a callback from a C function or static member function with one parameter and a return type.
- *
- * @SINCE_1_0.0
- * @param[in] function The function to call
- * @return A newly allocated Callback object, ownership transferred to caller
- */
-template<typename R, typename P1>
-inline CallbackBase* MakeCallback(R (*function)(P1))
-{
-  return new CallbackFunction(function);
-}
-
-/**
- * @brief Creates a callback from a C function or static member function with two parameters.
+ * @brief Creates a callback from a free function with parameter pack.
  *
- * @SINCE_1_0.0
- * @param[in] function The function to call
- * @return A newly allocated Callback object, ownership transferred to caller
- */
-template<typename P1, typename P2>
-inline CallbackBase* MakeCallback(void (*function)(P1, P2))
-{
-  return new CallbackFunction(function);
-}
-
-/**
- * @brief Creates a callback from a C function or static member function with two parameters and a return type.
- *
- * @SINCE_1_0.0
- * @param[in] function The function to call
- * @return A newly allocated Callback object, ownership transferred to caller
- */
-template<typename R, typename P1, typename P2>
-inline CallbackBase* MakeCallback(R (*function)(P1, P2))
-{
-  return new CallbackFunction(function);
-}
-
-/**
- * @brief Creates a callback from a C function or static member function with three parameters.
- *
- * @SINCE_1_0.0
- * @param[in] function The function to call
- * @return A newly allocated Callback object, ownership transferred to caller
- */
-template<typename P1, typename P2, typename P3>
-inline CallbackBase* MakeCallback(void (*function)(P1, P2, P3))
-{
-  return new CallbackFunction(function);
-}
-
-/**
- * @brief Creates a callback from a C function or static member function with three parameters and a return type.
- *
- * @SINCE_1_0.0
+ * @SINCE_1_9.33
  * @param[in] function The function to call
  * @return A newly allocated Callback object, ownership transferred to caller
  */
-template<typename R, typename P1, typename P2, typename P3>
-inline CallbackBase* MakeCallback(R (*function)(P1, P2, P3))
+template<typename R, typename... Args>
+inline CallbackBase* MakeCallback(R (*function)(Args... args))
 {
-  return new CallbackFunction(function);
+  return new CallbackBase(reinterpret_cast<CallbackBase::Function>(function));
 }
 
 /**