Search code examples
c++templatesc++11function-pointersperfect-forwarding

The perfect callback function


Goal : Obtain a callback function that will take any type of parameters as the callback function's parameters

.h
template <typename F, typename A>
void DelayedCallback(F&& CallbackFunction, A&& Args = NULL);

/

.cpp
void DelayedCallback(F&& CallbackFunction, A&& Args)
{
  //Timer function that received a function pointer to be the "callback"  function
  Timer((std::bind(std::forward<F>(CallbackFunction), std::forward<A>(Args)))())
}

/

DelayedCallback(&HUDExit);

void HUDExit() {}

/

ERROR : DelayedCallback(FName,float,F &&,A &&)' : could not deduce template argument for 'A'

What am I doing wrong? I'm new to most of these concept in c++, more of c# programmer

EDIT : It's not only about the error, I'm pretty sure it's not the only one I am making.


Solution

  • Your error message doesn't match the signature of DelayedCallback

    template <typename F, typename A>
    void DelayedCallback(F&& CallbackFunction, A&& Args = NULL)
    
    DelayedCallback(&HUDExit);
    

    That function signature and the usage you've shown will not produce an error message that says

    ERROR : DelayedCallback(FName,float,F &&,A &&)' : could not deduce template argument for 'A'

    But ignoring the template parameter mismatches, the code you've shown will also result in a similar error. The problem is that template parameters cannot be deduced from default arguments and A is treated as a non-deduced context in your example.

    From N3337, §14.8.2.5/5 [temp.deduct.type]

    The non-deduced contexts are:
    ...
    — A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done.

    Instead, you should change A to a parameter pack. That'll allow you to pass zero or more arguments to DelayedCallback.

    template <typename F, typename... A>
    void DelayedCallback(F&& CallbackFunction, A&&... Args)
    {
      //Timer function that received a function pointer to be the "callback"  function
      Timer((std::bind(std::forward<F>(CallbackFunction), std::forward<A>(Args)...))())
      // previous line is missing a semicolon at the very least
    }
    

    Once you fix all that, you'll run into the problem mentioned in the comments. You cannot split the declaration and definition of a function template between a header and source file as you would with a non-template. So implement DelayedCallback in the header itself as I have done above.