我正在用 C++ 实现观察者模式的变体。但是,由于我项目的性质,它不能使用任何虚拟成员函数,因为 vtable 查找和缓存未命中的总开销是不可接受的。
如果我通过虚拟成员函数创建接口,我会简单地编写以下内容:
template <class MessageType>
class MessageSubscriber {
public:
virtual void OnMessage(MessageType *message) = 0;
};
template <class MessageType>
class MessagePublisher {
public:
void AddSubscriber(MessageSubscriber<MessageType> *subscriber) {
subscribers.push_back(subscriber);
}
protected:
void Publish(MessageType *message) {
for (auto subscriber : subscribers)
subscriber.OnMessage(message);
}
private:
std::vector<MessageSubscriber<MessageType>*> subscribers;
};
然后,例如,我可以有MessageSubscriber
一些实现MessageType
,的类SafetyMessage
,如下所示:
class SafetyMessageSubscriberA : public MessageSubscriber<SafetyMessage> {
public:
virtual void OnMessage(SafetyMessage *message) override {
/* process message */
}
};
class SafetyMessageSubscriberB : public MessageSubscriber<SafetyMessage> {
public:
virtual void OnMessage(SafetyMessage *message) override {
/* process message */
}
};
class SafetyMessagePublisher : public MessagePublisher<SafetyMessage> {
public:
void Run {
/* manipulate message data */
this->Publish(&message);
}
private:
SafetyMessage message;
};
这将完成工作,但是,正如前面所强调的,vtable 查找开销在应用程序的上下文中是不可接受的,尽管它提供了多态便利,并且应用程序也需要它。然后,自然地,我尝试了几种围绕可以通过模板利用的静态多态性的方法。
我第一次尝试使用 CTRP,但在这种情况下它失败了,因为其中包含的指针在被调用MessagePublisher::subscribers
时必须指向同一个基类。MessagePublisher::Publish(MessageType *message)
因此,您不能有一些 CTRP 模式 MessageSubscriber<SafetyMessageSubscriberA>
,MessageSubscriber<SafetyMessageSubscriberB>
因为模板参数需要相同才能合法地允许两个对象进入MessagePublisher::subscribers
。
我最近对该问题的尝试使我尝试了成员函数模板专业化的一些变体,尽管没有成功。我在模式界面上尝试了以下变体:
class MessageSubscriber {
public:
template <class MessageType>
void OnMessage(MessageType *message);
};
class MessagePublisher {
public:
template <class MessageType>
void Publish(MessageType *message) {
for (auto subscriber: subscribers)
subscriber->OnMessage<MessageType>(message);
}
private:
std::vector<MessageSubscriber*> subscribers;
};
template<class MessageType>
void MessageSubscriber::OnMessageOnMessage(MessageType *message) {
/* "interface" call; do nothing */
}
使用以下实现:
class SafetyMessageSubscriberA : public MessageSubscriber {
public:
// declare for legal overload
template <class MessageType>
void OnMessage(MessageType *message);
};
class SafetyMessageSubscriberB : public MessageSubscriber {
public:
// declare for legal overload
template <class MessageType>
void OnMessage(MessageType *message);
};
template<>
void SafetyMessageSubscriberA::OnMessage<SafetyMessage*>OnMessage(SafetyMessage *message) {
/* process message */
}
template<>
void SafetyMessageSubscriberB::OnMessage<SafetyMessage*>OnMessage(SafetyMessage *message) {
/* process message */
}
但是,当我尝试这样做时,总是会调用基类MessagePublisher::Publish(SafetyMessage *message)
的通用实现,而不是为特定于.MessageSubscriber::OnMessage(MessageType *m)
SafetyMessage*
我是否按预期错误地专门化了功能模板,还是有另一种更有效的解决方案?对于与重载和成员模板专业化的概念有关的任何不精确的措辞,我提前道歉。