Search code examples
c++templates

How to use default argument values, when templating over a function?


I want to be able to wrap a function call with some arbitrary 'prefix' and 'postfix' code, like so:

template <typename Function, typename ... Args>
void WrappedCall(Function f, Args ... args)
{
    //Do something before the call...

    f(args...);

    //Do something after the call...
}

void Function(int def_val = 0)
{

}

Using this, submitting all arguments explicitly works perfectly well:

WrappedCall(Function, 0);

But attempting to make use of the default value fails ('too few arguments to function f(args...)'):

WrappedCall(Function);

How can I work around this? The structure of the code achieving this behavior can be completely different to the example I've written, but I would like, if possible, to maintain the simple calling pattern, as I want to use this on functions from some libraries that can have really long signatures.


Solution

  • You can use a lambda expression:

    WrappedCall([](){Function();} );
    

    Live Demo


    Default arguments are actually rather limited. This fails for the same reason:

    void(*f)(int) = Function;
    f();   // error too few arguments :/
    

    Somehow you need to turn Function into a callable whose type allows to be called without arguments. And the lambda achieves that.


    If your Function has more non-defaulted arguments this works as well:

    template <typename Function, typename ... Args>
    void WrappedCall(Function f, Args ... args)
    {
        //Do something before the call...
    
        f(args...);
    
        //Do something after the call...
    }
    
    void Function(int x,double y, float z,int def_val = 0)
    {
    
    }
    
    int main() {
        WrappedCall([](auto&&...args){Function(args...);},0,0.0,0.0);
    }
    

    Live Demo


    PS: I didn't consider perfect forwarding here, as it is also missing from your code, but you should definitely read about it.