Xirema Xirema - 11 months ago 138
C++ Question

How to Deduce Argument List from Function Pointer?

Given two or more example functions, is it possible to write templated code which would be able to deduce the arguments of a function provided as a template parameter?

This is the motivating example:

void do_something(int value, double amount) {
std::cout << (value * amount) << std::endl;
}

void do_something_else(std::string const& first, double & second, int third) {
for(char c : first)
if(third / c == 0)
second += 13.7;
}

template<void(*Func)(/*???*/)>
struct wrapper {
using Args = /*???*/;
void operator()(Args&& ... args) const {
Func(std::forward<Args>(args)...);
}
};

int main() {
wrapper<do_something> obj; //Should be able to deduce Args to be [int, double]
obj(5, 17.4); //Would call do_something(5, 17.4);
wrapper<do_something_else> obj2; //Should be able to deduce Args to be [std::string const&, double&, int]
double value = 5;
obj2("Hello there!", value, 70); //Would call do_something_else("Hello there!", value, 70);
}


In both uses of
/*???*/
, I am trying to work out what I could put there that would enable this kind of code.

The following doesn't appear to work, due to
Args
not being defined before its first use (along with what I have to assume are numerous syntax errors besides), and even if it did, I'm still looking for a version that doesn't require explicit writing of the types themselves:

template<void(*Func)(Args ...), typename ... Args)
struct wrapper {
void operator()(Args ...args) const {
Func(std::forward<Args>(args)...);
}
};

wrapper<do_something, int, double> obj;

Answer Source

With C++17 we can have auto template non-type parameters which make possible the Wrapper<do_something> w{} syntax 1).

As for deducing Args... you can do that with a specialization.

template <auto* F>
struct Wrapper {};

template <class Ret, class... Args, auto (*F)(Args...) -> Ret>
struct Wrapper<F>
{
    auto operator()(Args... args) const
    {
        return F(args...);
    }
};
Wrapper<do_something> w{};
w(10, 11.11);

1) Without C++17 it's impossible to have the Wrapper<do_something> w{} nice syntax.

The best you can do is:

template <class F, F* func>
struct Wrapper {};

template <class Ret, class... Args, auto (*F)(Args...) -> Ret>
struct Wrapper<Ret (Args...), F>
{
    auto operator()(Args... args) const
    {
        return F(args...);
    }
};
Wrapper<declype(do_something), do_something> w{};
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download