Я пытаюсь разработать конечный автомат на основе событий в течение пары часов, и мне не удается определить, почему шаблонные классы ниже не совпадают.
По сути, 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, то есть EventListener<StateEvent, StateEventPublisher>, а StateEventPublisher - это EventPublisher<StateEvent> ?! Что я делаю не так?!
Не уверен, что мне что-то не хватает, но я нигде не вижу, чтобы Listener был определен.
@GillBates typedef EventListener<Event, EventPublisher> Listener;
да, учитывая struct A{}; и struct B: A{} и template<typename T> struct C{}, типы C<A> и C<B> различны и не связаны





В объявлении 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;
}
Блестяще! Спасибо!
Он компилируется с
using StateEventPublisher = EventPublisher<StateEvent>;.