c++ - 如何将下面的模板类泛化为调用任何函数?

标签 c++ c++11 templates methods lambda

#include <map>
#include <functional>

template<typename... Args>
class Listner {
public:
    template<typename T>
    void attachListner(T *t) {
        m_listenerCallbacks.insert(std::make_pair(reinterpret_cast<void*>(t), [&t](Args... args){t->callback(args...); }));
    }

    template<typename T>
    void detachListner(T *t) {
        m_listenerCallbacks.erase(reinterpret_cast<void*>(t));
    }

    void notify(Args... args) {
        for (auto l : m_listenerCallbacks)
            l.second(args...);
    }
private:
    std::map<void*, std::function<void(Args...)>> m_listenerCallbacks;
};

使用上面的 Listner 类,我可以注册具有名为 callback 的公共(public)方法的对象。是否有可能以方法名称 (callback) 也可以作为模板参数传递的方式概括 Listner 类。

最佳答案

以下是基于可能适合您的示例代码的可能解决方案:

#include <map>
#include <functional>

template<typename>
struct Listner;

template<typename R, typename... Args>
struct Listner<R(Args...)> {
    template<typename T, R(T::*M)(Args...) = &T::callback>
    void attachListner(T *t) {
        m_listenerCallbacks.insert(std::make_pair(static_cast<void*>(t), [t](Args... args){ (t->*M)(args...); }));
    }

    void notify(Args... args) {
        for (auto l : m_listenerCallbacks)
            l.second(args...);
    }

private:
    std::map<void*, std::function<void(Args...)>> m_listenerCallbacks;
};

struct A {
    void f(int, char) {}
    void f(int, double) {}
    void f(int) {}
};

int main() {
    A a;
    Listner<void(int, char)> l;
    l.attachListner<A, &A::f>(&a);
    l.notify(0, 'c');
}

基本思想是您必须完全指定函数类型(参见 Listner<void(int, char)> )。唯一的参数列表是不够的。
我们可以通过类模板的部分特化来做到这一点:

template<typename>
struct Listner;

template<typename R, typename... Args>
struct Listner<R(Args...)> {
    // ...
};

完成后,我们可以使用该类型来检测作为模板参数的正确重载:

template<typename T, R(T::*M)(Args...) = &T::callback>
void attachListner(T *t) {
    // ...
}

请注意,我设置了一个默认值 (&T::callback),以便您可以通过以下方式调用它:

l.attachListner<A, &A::f>(&a);

如果你想使用不同的成员函数,或者:

l.attachListner(&a);

如果A有一个名为 callback 的成员方法并且您想像以前一样使用它。

关于c++ - 如何将下面的模板类泛化为调用任何函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44950461/

相关文章:

c++ - Constexpr 指针值

templates - 尝试将参数传递给 url 时索引超出范围

c++ - 检查一组类型是否是另一组类型的子集

c++ - 从 QMap 中调用成员函数

c++ - 根据编译时常量,使用 #define'd 或 typedef'ed 相同的标识符是否被认为是可接受的做法?

c++ - Windows下4K屏幕截图并直接保存到缓冲区

c++ - 修改 Makefile 以支持 c++11

c++ - 如何从 std::list 实现 O(1) 删除

C++ 为特定模板特化添加重载方法

c++ - 具有传递引用对象的类会产生编译错误