【问题标题】:Inheritance and templates, a weird behaviour继承和模板,一种奇怪的行为
【发布时间】:2018-08-26 16:33:32
【问题描述】:

我正在尝试开发基于事件的状态机几个小时,但我无法确定为什么下面的模板类不匹配。 基本上,State 发布事件,StateMachine 监听它们。这是一个sn-p:

#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&lt;StateEvent, StateEventPublisher&gt;,而StateEventPublisherEventPublisher&lt;StateEvent&gt;,为什么机器不能附加到状态?!我做错了什么?!

【问题讨论】:

  • using StateEventPublisher = EventPublisher&lt;StateEvent&gt;;编译。
  • 不确定我是否遗漏了什么,但我没有看到 Listener 在任何地方定义。
  • @GillBates typedef EventListener&lt;Event, EventPublisher&gt; Listener;
  • 是的,鉴于 struct A{};struct B: A{}template&lt;typename T&gt; struct C{} 类型 C&lt;A&gt;C&lt;B&gt; 是不同且不相关的

标签: c++ c++11 templates inheritance observer-pattern


【解决方案1】:

EventPublisher&lt;StateEvent&gt; 声明中,EventPublisher 期望侦听器是 EventListener&lt;StateEvent, EventPublisher&lt;StateEvent&gt;&gt;,而您提供的侦听器是 EventListener&lt;StateEvent, StateEventPublisher&gt;,这是不相关的类型(即使 StateEventPublisher 继承自 EventPublisher&lt;StateEvent&gt;)。

有几种方法可以解决这个问题,例如使用 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;
}

online compiler

【讨论】:

  • 太棒了!谢谢!
猜你喜欢
  • 2012-04-30
  • 2012-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多