c++ - 继承和模板,一种奇怪的行为
问题描述
我正在尝试开发一个基于事件的状态机几个小时,但我无法确定为什么下面的模板类不匹配。基本上,State
发布事件并StateMachine
监听它们。这是一个片段:
#include <iostream>
#include <vector>
// Interface for event listening
template <typename Event, typename Sender>
class EventListener
{
public:
virtual ~EventListener() = default;
virtual void onEvent(const Sender* sender, const Event& data) = 0;
};
// Abstract class for event publishing
template <typename Event>
class EventPublisher
{
public:
typedef EventListener<Event, EventPublisher> Listener;
virtual ~EventPublisher() = default;
// Queues an event listener
void attach(Listener* listener) {
listeners.push_back(listener);
}
protected:
// Publishes an event among all registered listeners
void publish(const Event& e) {
for (Listener* listener : listeners) {
listener->onEvent(this, e);
}
}
private:
std::vector<Listener*> listeners;
};
// Concrete publisher & listener
class StateEvent {};
class StateEventPublisher : public EventPublisher<StateEvent> {};
class StateEventListener : public EventListener<StateEvent, StateEventPublisher> {};
class State : public StateEventPublisher {
public:
void foo() {
publish(StateEvent());
}
};
class StateMachine final : public StateEventListener {
private:
void onEvent(const StateEventPublisher* sender, const StateEvent& e) override {}
};
int main()
{
State state;
StateMachine machine; // Is a StateEventListener, which is a EventListener<StateEvent, StateEventPublisher>, whereas StateEventPublisher is a EventPublisher<StateEvent>
state.attach(&machine); // Incompatible with EventListener<StateEvent, EventPublisher<StateEvent>>*
state.foo();
return 0;
}
StateEventListener
如果机器是 a ,那是 a EventListener<StateEvent, StateEventPublisher>
,而 aStateEventPublisher
是 a ,为什么机器不能附加到状态EventPublisher<StateEvent>
?!我究竟做错了什么?!
解决方案
在EventPublisher<StateEvent>
声明EventPublisher
中期望侦听器是EventListener<StateEvent, EventPublisher<StateEvent>>
,而您提供的侦听器EventListener<StateEvent, StateEventPublisher>
是不相关的类型(即使StateEventPublisher
继承自EventPublisher<StateEvent>
)。
可能有几种方法可以解决这个问题,例如使用 CRTP:
// Interface for event listening
template <typename Event, typename Sender>
class EventListener
{
public:
virtual ~EventListener() = default;
virtual void onEvent(const Sender* sender, const Event& data) = 0;
};
// Abstract class for event publishing
template <typename Event, typename Sender>
class EventPublisher
{
public:
typedef EventListener<Event, Sender> Listener;
virtual ~EventPublisher() = default;
// Queues an event listener
void attach(Listener* listener) {
listeners.push_back(listener);
}
protected:
// Publishes an event among all registered listeners
void publish(const Event& e) {
for (Listener* listener : listeners) {
listener->onEvent(static_cast<Sender *>(this), e);
}
}
private:
std::vector<Listener*> listeners;
};
// Concrete publisher & listener
class StateEvent {};
class StateEventPublisher : public EventPublisher<StateEvent, StateEventPublisher> {};
class StateEventListener : public EventListener<StateEvent, StateEventPublisher> {};
class State : public StateEventPublisher {
public:
void foo() {
publish(StateEvent());
}
};
class StateMachine final : public StateEventListener {
private:
void onEvent(const StateEventPublisher* sender, const StateEvent& e) override {}
};
int main()
{
State state;
StateMachine machine; // Is a StateEventListener, which is a EventListener<StateEvent, StateEventPublisher>, whereas StateEventPublisher is a EventPublisher<StateEvent>
state.attach(&machine); // Incompatible with EventListener<StateEvent, EventPublisher<StateEvent>>*
state.foo();
return 0;
}
推荐阅读
- android-layout - 如何每行并排列出布局中的项目 - android
- c++ - 我应该使用什么样的数据结构来实现 UPGMA?
- c# - 您的 SQL 语法错误,.net 的 mysql 连接器
- hibernate - JpaRepository 进行意外更新
- session - 当我们已经有 cookie 时,为什么还需要 session ?
- c# - 为什么 C# 编译器会为 NULL 和数字比较产生结果?
- angular - GZip 在 Webpack 2.5.1 中不起作用
- android - MPAndroidChart BarChart 在重绘时不考虑条形宽度
- javascript - 使用 jquery 关闭当前模态并打开新模态
- java - 使用spring数据mongodb进行组聚合