如何从函数指针中删除参数列表?

Xir*_*ema 8 c++ templates template-meta-programming

给定两个或更多示例函数,是否可以编写模板化代码,这些代码能够推导出作为模板参数提供的函数的参数?

这是一个激励的例子:

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);
}
Run Code Online (Sandbox Code Playgroud)

在两种用途中/*???*/,我试图弄清楚我可以放在哪里,这将启用这种代码.

以下似乎不起作用,因为它Args没有在第一次使用之前被定义(除了我必须假设的还有许多语法错误),即使它确实如此,我仍然在寻找一个版本不能要求明确写出类型本身:

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

wrapper<do_something, int, double> obj;
Run Code Online (Sandbox Code Playgroud)

bol*_*lov 6

使用C++ 17,我们可以使用自动模板非类型参数来实现Wrapper<do_something> w{}语法1).

至于演绎,Args...你可以通过专业化来做到这一点.

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...);
    }
};
Run Code Online (Sandbox Code Playgroud)
Wrapper<do_something> w{};
w(10, 11.11);
Run Code Online (Sandbox Code Playgroud)

1)没有C++ 17,就不可能拥有Wrapper<do_something> w{}漂亮的语法.

你能做的最好的事情是:

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...);
    }
};
Run Code Online (Sandbox Code Playgroud)
Wrapper<declype(do_something), do_something> w{};
Run Code Online (Sandbox Code Playgroud)

  • @Xirema C++ 17正处于实施的早期阶段.clang可以编译它没有问题:https://godbolt.org/g/DyArxa (2认同)

gez*_*eza 5

使用 C++17,你可以这样做:

template <auto FUNC, typename = decltype(FUNC)>
struct wrapper;

template <auto FUNC, typename RETURN, typename ...ARGS>
struct wrapper<FUNC, RETURN (*)(ARGS...)> {
    RETURN operator()(ARGS ...args) {
        return FUNC(args...);
    }
};
Run Code Online (Sandbox Code Playgroud)

我从 WF 的回答中学到了这个技巧