在虚拟成员函数上使用模板的替代方法是什么?

时间:2018-02-03 20:49:42

标签: c++ templates

我正在创建一个简单的事件系统,其中可以针对特定主题通知多个侦听器,并且当触发事件时,它可以将通用有效负载传递给事件,并且侦听器将匹配触发事件的格式。但是,由于无法在虚拟函数上使用模板,我还能做到这一点吗?

class AEventListener
{
public:

    template<class T>
    struct PayloadObject {
        T obj;
    };

    explicit AEventListener();
    virtual ~AEventListener();

//error here because T is undefined. Each PayloadObject may have a different type
    virtual void notify(vector<shared_ptr<PayloadObject<T>>> payload) = 0;
};

当事件主题订阅了一个侦听器时,会调用notify方法,但我想要一种只是将一大堆随机对象传递给侦听器的通用方法。

例如

fireEvent("test.topic", Payload { 0, "hello", 123 });
//...
listener.notify(payload);

我将如何在C ++中使用它?

我设法绕过这个,虽然我不认为这是最好的方式,可能会降低性能。

template<class T>
struct PayloadObject : public APayloadObject {
    T obj;

    PayloadObject(T obj) {
        this->obj = obj;
    }

    ~PayloadObject() override {

    };

};

struct APayloadObject {
    virtual ~APayloadObject();
};

烧成:

vector<shared_ptr<APayloadObject>> payload;
payload.push_back(shared_ptr<PayloadObject<int>>(new PayloadObject<int>(5))); //payload[0] = int - 5
Events::fire(EventKeys::DISCONNECTION_EVENT, payload);

通知:

shared_ptr<PayloadObject<int>> number = dynamic_pointer_cast<PayloadObject<int>>(payload[0]);
int id = number.get()->obj; //payload[0] = int - 5

1 个答案:

答案 0 :(得分:2)

一种简单的方法是为Payload对象提供公共基础或公共接口。所以它们不是模板类。

struct Payload {
  virtual ~Payload() = default;
  virtual std::string foo() const;
  virtual std::string bar() const;
};

另一种方法是为有效负载对象使用变量类型:

using Message_t = boost::variant<A, B, C>;

然后让AEventListener采用Message_t类型,这样就不需要将成员函数作为模板。

class AEventListener
{
public:
    virtual ~AEventListener();

    virtual void notify(std::vector<Message_t> payload) = 0;
};

在C ++ 17中,您可以使用std::variant代替boost。

另一种方法是跳过使用变体,只需使它成为监听器必须实现三种不同的功能,每种类型一种:

class AEventListener
{
public:
    virtual ~AEventListener();

    virtual void notifyA(A payload) = 0;
    virtual void notifyB(B payload) = 0;
    virtual void notifyC(C payload) = 0;
};

更一般地说,在C ++中很难创建类似&#34;可以使用任何特定类型的参数调用的函数对象&#34;。这部分原因是因为......它不是很有用,你可以用任何类型的数据来做一些你不能做的事情。

所以我建议你仔细考虑改进你的事件监听器概念,并更具体地说明这类对象应该被认为是必须要做的。