Наследование и шаблоны, странное поведение - PullRequest
0 голосов
/ 26 августа 2018

Я пытаюсь разработать конечный автомат на основе событий в течение пары часов и не могу определить, почему приведенные ниже шаблоны не соответствуют друг другу.По сути, 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> ?!Что я делаю не так?!

1 Ответ

0 голосов
/ 26 августа 2018

В 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;
}

онлайн-компилятор

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...