指向可变参数函数模板的指针

Rub*_*ens 5 c++ templates function-pointers variadic-templates c++11

我有一个简单的类A,提供可变参数函数模板.此函数使用内部的私有数据A,但函数本身是公共的.课程如下:

class A {
public:

    A() :
    _bla("bla: ") {
    }

    template <class T>
    void bar(const T& value) {
        std::cout << _bla << value << std::endl;
    }

    template <class H, class... T>
    void bar(const H& value, const T&... data) {
        std::cout << _bla << value << std::endl;
        bar(data...);
    }

private:
    const std::string _bla;
};
Run Code Online (Sandbox Code Playgroud)

在一个名为foo.hpp的单独文件中,我有一个函数foo(),它应该能够接收并使用该函数a.bar()作为参数:

int main(int argc, char *argv[]) {    
    A a;
    a.bar(1, "two", 3, 4);
    foo(&a.bar);
}
Run Code Online (Sandbox Code Playgroud)

我不太确定从哪里开始,但我尝试了以下 - 这不起作用.我该怎么做才能正确:

template <typename... T>
inline void foo(void (bar *)(const T&...)) {
    unsigned int x(0), y(0), z(0);
    bar(x, y, z);
}
Run Code Online (Sandbox Code Playgroud)

奖金问题:有没有办法打电话:

foo(&a.bar);
Run Code Online (Sandbox Code Playgroud)

但也呼吁fooa.bar绑定到一些参数,如:

foo(&(a.bar(p1, p2));
Run Code Online (Sandbox Code Playgroud)

我可以简单地添加p1,并p2foo自身的定义,就像在:

foo(p1, p2, &a.bar);
Run Code Online (Sandbox Code Playgroud)

但如果我之前可以添加这些参数,那么在语义上会更好.

And*_*owl 8

您无法在不实例化的情况下传递函数模板的地址,因为它被视为整个重载集(无论模板是否为可变参数).但是,您可以将其包装在通用仿函数中:

struct bar_caller
{
    template<typename... Ts>
    void operator () (A& a, Ts&&... args)
    {
        a.bar(std::forward<Ts>(args)...);
    }
};
Run Code Online (Sandbox Code Playgroud)

然后让您的函数foo()定义如下:

template<typename F>
inline void foo(A& a, F f) {
    unsigned int x(0), y(0), z(0);
    f(a, x, y, z);
}
Run Code Online (Sandbox Code Playgroud)

所以你的函数调用main()将成为:

int main()
{
    A a;
    a.bar(1, "two", 3, 4);
    foo(a, bar_caller());
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,目前在C++中没有办法在没有定义单独的类的情况下轻松地在函子中包装重载集 - 如上所述bar_caller.

编辑:

如果你不想A直接传递一个对象foo(),你仍然可以让你bar_caller封装一个对必须调用A该函数的对象的引用bar()(只需要处理对象的生命周期,这样你就不会让那个引用悬空了):

struct bar_caller
{
    bar_caller(A& a_) : a(a_) { }

    template<typename... Ts>
    void operator () (Ts&&... args)
    {
        a.bar(std::forward<Ts>(args)...);
    }

    A& a;
};
Run Code Online (Sandbox Code Playgroud)

然后你可以重写foo(),main()如下:

template<typename F>
inline void foo(F f) {
    unsigned int x(0), y(0), z(0);
    f(x, y, z);
}

int main()
{
    A a;
    a.bar(1, "two", 3, 4);
    foo(bar_caller(a));
}
Run Code Online (Sandbox Code Playgroud)