Search code examples
c++templatesvariadic-templatesfunction-templates

Allow function of variadic argument count as template function argument


In C++ we can pretty easily define template function arguments as seen in this question. However, this only allows functions with a defined parameter list and return value.

We can make those types template parameters like this:

template<typename R, typename P, R(*Func)(P)>
R proxy_func(P arg)
{
    // do some stuff...
    R&& res{ Func(std::forward(arg)) };
    // do some more stuff...
    return res;
}

However, here we are still limited to a fixed number of parameters.

An attempt like the following won't compile (at least on MSVC 19.24.28315), because "template parameter 'Func' cannot be used because it follows a template parameter pack and cannot be deduced from the function parameters of 'proxy_func'".

template<typename R, typename... P, R(*Func)(P...)>
R proxy_func(P... args)
{
    // do some stuff...
    R&& res{ Func(std::forward(args)...) };
    // do some more stuff...
    return res;
}

So what are the options for allowing an arbitrary function as template argument and - just as importantly - allow its parameters to be used as the parameters for, say, the function template it's used in (like in proxy_func above)? Ideally, I would be able to call proxy_func with just any function as (ideally single) template argument Func and be able to apply its (proxy_func's) arguments to Func.


Edit: I am particularly interested in having a function-instance as template argument (e. g. to allow template instantiations of proxy_func to apply compile-time optimisations based on individual Funcs).


Solution

  • In some sense, the Q&A you link is the complicated way. The simple way is:

    template <typename F>
    void foo(F f) {
        f();    // call the function
    }
    

    In your case the return value can be deduced and the argument types can be deduced from the parameters to foo. Note that they need not necessarily match exactly the argument types of f as long as f can be called with them:

    template <typename F,typename ... Args>
    auto foo( F f, Args ... args) {
        return f(args...);    // call the function
    }
    

    For the sake of brevity I ommitted forwarding and storing the result of the call in a temporary, but the answer still applies.

    In case you want to have the function itself, not its type as template parameter (sorry I missed that part first) this still works:

    template <auto f,typename ... Args>
    auto foo(Args ... args) {
        return f(args...);    // call the function
    }
    

    However, this won't work in case f is a lambda. See here for details: https://en.cppreference.com/w/cpp/language/template_parameters#Non-type_template_parameter