是否适合模拟模板化数据成员?

时间:2015-11-21 05:12:04

标签: c++ templates observer-pattern

我正在尝试实现Observer模式的变体,它缓冲不同的事件类型并陷入僵局。

这就是我想要的:

class Foo
{
    /* ..... */
    std::vector<Base*> buf;

    template<typename T>
    void newEvent(T ev)
    {
        /* I give the list of observers to each event.
         * There are billions of events coming in for
         * each run of the application 
         */
        buf.push_back(new Event<T>(ev, &observers<T>));
    }

    /* Illegal, templated data members */
    template<typename T>
    std::vector<Observer<T>*> observers;

    template<typename T>
    void attach(Observer<T> obs)
    {
        /* Each type has its own list of observers */
        observers<T>.push_back(obs);
    }
    /* ..... */
};

稍后刷新缓冲区时......

void Foo::flush()
{
    for (Base* ev : buf) 
    {
        ev->notifyAll();
        delete ev;
    }
}

template <typename T>
class Event : public Base
{
    /* ..... */
    Event(T t, const std::vector<Observer*>& o):observers(o),payload(t){}
    void notifyAll() 
    {
        for (Observer* obs : observers)
            obs->onNotify(this->payload);
    }
};

模板中的类型只是来自外部的POD。当它被打包时,我给它一个观察者列表。现在我可以在Foo中手动定义每种类型的观察者向量,但我希望能够支持未定义数量的“事件”类型。

我知道一个类的模板化数据成员是非法的,即使在c ++ 14中,还有一些支持模板化变量。

继续沿着这条路走下去是否有意义?最初我在每个'事件'类型中静态地拥有“观察者”部分,但我试图摆脱尽可能多的全局状态,以实现可测试性。

我试图将事情转移到类模板中,相反,但那时我也遇到了麻烦。

template <typename T>
class EventHandler //can't think of a good name for this demon baby
{
    public Base* create(T t); //when I create a new event, I need the observer list
    public void attach(Observer<T>);
    private std::vector<Observer<T>*> observers;
};

class Buffer
{
    /* ..... */
    EventHandler<EventType1> thing1;
    EventHandler<EventType2> thing2;
    EventHandler<EventType3> thing3;

    template<typename T>
    public newEvent(T ev) //I could just explicitly say the type here
    {
        buf.push_back(thing?.create(ev)); //how to know which one to use?
    }
};

我从另一个角度遇到同样的问题:/。我还想过只是打开类型ID,但认为它很混乱。

1 个答案:

答案 0 :(得分:1)

一种方法是使用std::type_index

class event_handler_base{
    public:
        virtual ~event_handler_base(){}
};

template<typename T>
class event_handler: public event_handler_base{
    public:
        void handle(T ev){ /* handle event */ }
};

class my_special_class{
    public:
        ~my_special_class(){
            for(auto &&p : handlers)
                delete p.second;
        }

        template<typename T>
        void new_event(T ev){
            get_handler<T>().handle(ev);
        }

        template<typename T>
        event_handler<T> &get_handler(){
            static std::type_index ti(typeid(T));
            auto it = handlers.find(ti);
            if(it == handlers.end())
                it = handlers.emplace(ti, new event_handler<T>()).first;

            return dynamic_cast<event_handler<T>&>(*it->second);
        }

        std::unordered_map<std::type_index, event_handler_base*> handlers;
};

如果你能找出编译时的答案,我不会喜欢这种方法,但它仍然很有趣。总是更喜欢编译时间成本而非运行时间成本。