[英]C++ - Pass member functions of any class to another class
我正在编写一个模板 class ,它将为我的应用程序中需要它的每个组件实现一个监听器接口。 我希望一个组件能够侦听已侦听的 object 中单个字段的更改。 每个 object 的字段由一个枚举表示,我有一个简单的 Notifier/Publisher 可以很好地工作:
template <typename EFieldsEnum>
class AbstractNotifier
{
public:
void addListener(EFieldsEnum listenedField, INotifierListener<EFieldsEnum>* listener)
{
if (_listeners.find(listenedField) == _listeners.cend())
{
std::unordered_set<INotifierListener<EFieldsEnum>*> listeners;
listeners.insert(listener);
_listeners.emplace(listenedField, listeners);
}
else
{
_listeners.find(listenedField)->second.insert(listener);
}
}
void notify(EFieldsEnum updatedField)
{
for (INotifierListener<EFieldsEnum>* listener : _listeners[updatedField])
{
listener->onUpdate(updatedField);
}
}
protected:
std::unordered_map<EFieldsEnum, std::unordered_set<INotifierListener<EFieldsEnum>*>> _listeners;
};
我正在尝试稍微更改方法签名,以便通过传递将作为回调调用的void()方法来注册每个侦听组件,而不是实现onUpdate泛型方法后跟 switch case。 理想情况下,我希望我的监听组件(比如 Component1)注册,而不必为我将拥有的每种类型的 Notifier 定义一个特定的 Listener 接口,如下所示:
notifier.addListener(FieldEnum::MyField1, this, &Component1::onMyField1Updated);
然后 Component2 也可以这样注册:
notifier.addListener(FieldEnum::MyField1, this, &Component2::someOtherMethod);
没有 Component1 和 Component2 需要实现一个通用接口。 这可能吗? 我正在努力弄清楚什么类型通常代表通过的成员方法:
class IListener {};
void (IListener::*ListenerCallback)();
template <typename EFieldsEnum>
class AbstractNotifier
{
public:
void addListener(EFieldsEnum listenedField, IListener* listener, ListenerCallback listenerCallback)
{
std::pair<IListener*, ListenerCallback> pairToAdd = std::make_pair<IListener*, ListenerCallback>(listener, ListenerCallback);
if (_listeners.find(listenedField) == _listeners.cend())
{
std::unordered_set<std::pair<IListener*, ListenerCallback>> listenersAndCallbacks;
listenersAndCallbacks.insert(pairToAdd);
_listeners.emplace(listenedField, listenersAndCallbacks);
}
else
{
_listeners.find(listenedField)->second.insert(pairToAdd);
}
}
void notify(EFieldsEnum updatedField)
{
for (const std::pair<IListener*, ListenerCallback>& listenerAndCallback : _listeners[updatedField])
{
IListener* listener = listenerAndCallback.first;
ListenerCallback listenerCallback = listenerAndCallback.second;
listener->*listenerCallback();
}
}
protected:
std::unordered_map<EFieldsEnum, std::unordered_set<std::pair<IListener*, ListenerCallback>>> _listeners;
};
使用std::function<void()>
这是您的AbstractNotifier
的一个稍微简化的版本,它将接受来自任何 class(或根本没有 class)的回调:
template <typename EFieldsEnum>
class AbstractNotifier
{
public:
void addListener(EFieldsEnum listenedField, std::function<void()> listenerCallback)
{
listeners_[listenedField].push_back(listenerCallback);
}
// Helper method template to wrap member function pointers
template <typename Listener>
void addListener(EFieldsEnum listenedField, Listener* listener, void(Listener::*listenerCallback)())
{
addListener(listenedField, [=]() { (listener->*listenerCallback)(); });
}
void notify(EFieldsEnum updatedField)
{
for (auto& callback : listeners_[updatedField])
{
callback();
}
}
protected:
std::unordered_map<EFieldsEnum, std::vector<std::function<void()>>> listeners_;
};
请注意,我放弃了您当前实现所具有的“唯一性”约束并使用了std::vector
。 这是因为很难或不可能真正比较std::function
s,而且很容易得到看起来非常不同的std::function
s,最终回调相同的底层代码。
即以下所有三个最终都调用同一个成员 function,但持有完全不同的类型,不能轻易比较:
// Different lambdas, so different types
std::function<void()> f1([&someObject]() { someFunc.foo(); });
std::function<void()> f2([&someObject]() { someFunc.foo(); });
std::function<void()> f3(std::bind(&SomeType::foo, someObject));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.