我正在尝试实现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,但认为它很混乱。
答案 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;
};
如果你能找出编译时的答案,我不会喜欢这种方法,但它仍然很有趣。总是更喜欢编译时间成本而非运行时间成本。