C++ 模拟模板化数据成员是否合适?
我正在尝试实现一种观察者模式的变体,它缓冲了不同的事件类型,并陷入了僵局 这就是我想要的:C++ 模拟模板化数据成员是否合适?,c++,templates,observer-pattern,C++,Templates,Observer Pattern,我正在尝试实现一种观察者模式的变体,它缓冲了不同的事件类型,并陷入了僵局 这就是我想要的: class Foo { /* ..... */ std::vector<Base*> buf; template<typename T> void newEvent(T ev) { /* I give the list of observers to each event. * There are bill
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);
}
/* ..... */
};
class-Foo
{
/* ..... */
std::载体buf;
模板
无效新事件(ev)
{
/*我给每个活动的观察员名单。
*有数以十亿计的事件即将发生
*应用程序的每次运行
*/
buf.推回(新事件(ev和观察员));
}
/*非法的、模板化的数据成员*/
模板
向量观测器;
模板
无效附加(观察员obs)
{
/*每种类型都有自己的观察者列表*/
观察员:推回(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);
}
};
void Foo::flush()
{
用于(基准*ev:buf)
{
ev->notifyAll();
删除电动汽车;
}
}
模板
班级活动:公共基地
{
/* ..... */
事件(T,const std::vector&o):观察者(o),有效载荷(T){}
void notifyAll()
{
用于(观察员*obs:观察员)
obs->onNotify(此->有效负载);
}
};
模板中的类型只是从外部传入的一个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?
}
};
模板
类EventHandler//想不出这个恶魔宝宝的好名字
{
public Base*create(T);//创建新事件时,需要观察者列表
公众(观察员);
私人std::病媒观察者;
};
类缓冲区
{
/* ..... */
事件处理程序1;
事件处理程序2;
事件处理程序3;
模板
public newEvent(T ev)//我可以在这里显式地说类型
{
buf.push_back(thing?.create(ev));//如何知道使用哪一个?
}
};
我从另一个角度遇到了同样的问题:/。我也想过只打开类型id,但觉得很混乱。一种方法是使用:
类事件处理程序\u基{
公众:
虚拟~event_handler_base(){}
};
模板
类事件处理程序:公共事件处理程序{
公众:
无效句柄(ev){/*句柄事件*/}
};
上课我的特别课{
公众:
~my_special_class(){
用于(自动和p:处理程序)
删除第二页;
}
模板
无效新事件(T ev){
get_handler().handle(ev);
}
模板
事件处理程序&获取处理程序(){
静态std::type_索引ti(typeid(T));
autoit=handlers.find(ti);
if(it==handlers.end())
it=handlers.emplace(ti,newevent_handler())。首先;
返回动态_cast(*it->second);
}
std::无序的_映射处理程序;
};
如果您能找到编译时的答案,我不喜欢这种方法,但它仍然很有趣。总是喜欢编译时成本而不是运行时成本。听起来像是一个
std::unordered_map
使用std::type_index
作为键。@T.C.有趣的是,我写的答案和你评论时说的一模一样
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;
};