#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/