Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to invoke a variadic template function without explicit specialization?

I was trying to write a function to forward arguments for a variadic template function, similar to std::invoke. Here is the code:

#include <functional>

template<class... Args>
void f(Args&&... args) { }

template<template<class...> class F, class... Args>
void invoke(F<Args...> f, Args&&... args) {
    f(std::forward<decltype(args)>(args)...);
}

int main() {
    invoke(f, 1, 2, 3);
    std::invoke(f, 1, 2, 3);
}

However, both my invoke and std::invoke fails to compile. g++ complains that it couldn't deduce template parameter template<class ...> class F. So is it possible to invoke a variadic template function without explicit template specialization?

like image 383
debug18 Avatar asked Mar 07 '23 07:03

debug18


2 Answers

Note that a function template represents a family of functions. When you, say, pass it to a function it needs to resolve to a certain specialization of the template. I understand what you're trying to do with the parameter of your custom invoke (capture the function template as a template) but sadly this will work only with class templates, never function templates.

You'd need another level of indirection. Namely, passing a functor or lambda that forwards the arguments to f:

invoke([](auto&&... xs) { f(decltype(xs)(xs)...); }, 1, 2, 3);

The difference is that now the argument is a class non-template so it can be deduced by your invoke.

With this change comes the additional requirement that you change your function to fully deduce the first parameter:

template<class F, class... Args>
void invoke(F&& f, Args&&... args) {
  f(forward<Args>(args)...);
}
like image 195
David G Avatar answered Mar 08 '23 20:03

David G


If function is wrapped inside of template class then you should be able to pass this template class as template template parameter:

#include <functional>

template<class... Args> struct Wrap
{
    static void f(Args&&... args) { }
};

template<template<class...> class F, class... Args>
void invoke(Args&&... args) {
    Wrap<Args...>::f(std::forward<Args>(args)...);
}

int main() {
    invoke<Wrap>(1, 2, 3);
}

online compiler

like image 23
user7860670 Avatar answered Mar 08 '23 21:03

user7860670