How to have a template argument with arbitraty type?

Viewed 43

I need to wrap various free functions with a common logic, but I don't want to write the wrapping code multiple times. The wrapped functions need to be "plain" free-functions (because I want to export them again for external use), hence I need to use a template. This is how far I've got:

#include <mutex>

std::mutex mutex;

void func1(int i){
}
int func2(int a, int b){
  return a-b;
}
// ... imagine more functions here

template<typename FN, FN p, typename... Args>
auto forward(Args... args) -> decltype(p(args...)) {
  auto lock = std::unique_lock<std::mutex>{mutex};
  return p(args...);
}

template<typename FN, FN p>
auto forwarder() -> FN {
  return &forward<FN, p>;
}

int main(){
  forwarder<decltype(&func1), &func1>();
  forwarder<decltype(&func2), &func2>();
}

This snippet works and does what I want, however I still need to specify the function name twice for the instantiation (once in the first template argument with decltype and once in the second argument). Is there a way that I can instantiate the forwarding template in a way that I only have to specify the function once? I.e. something along the lines of:

forwarder<&func1>();

Or can I achieve the goal some better way? I would hate to have to resort to a preprocessor macro or having to specify each function twice.

1 Answers

C++17 introduced auto non-type template parameters for exactly this use case:

template<auto Func, typename... Args>
auto forward(Args&&... args)
{
    auto lock = std::unique_lock<std::mutex>{mutex};
    return Func(std::forward<Args>(args)...);
}

void func1(int i)
{
    //...
}

int main()
{
    forward<&func1>(42);
}

Here the type of Func will be deduced based on the type of object passed as forward's first template parameter.

Related