есть набор структур с данными, для каждой структуры есть код который ее обрабатывает, для этого кода есть общий "контекст" (данные) в котором он работает каждая структура имеет свой id, допустим целое число
по сети, или из файла, приходит буфер который содержит данные какой-то структуры, и id этой структуры надо написать код который по полученному id определит какая структура лежит в буфере и выполнит код ее обработки. (каждая структура имеет конструктор который загружает ее из буфера)
допустим, что "контекст" - это класс, код обработки - метод этого класса, перегруженный для каждой структуры. (все можно сделать наоборот, например код обработки- метод структуры, и ему передается контекст)
| Код | struct Foo { static const id_t id = 1; Foo(buf_t& buf) {/*код загрузки из буфера buf*/} /*данные*/ ......... }; struct Bar { static const id_t id = 2; Bar(buf_t& buf) {/*код загрузки из буфера buf*/} /*данные*/ ......... }; struct Context { /*данные*/ ...........
Process( Foo & data ) {/*код обработки*/} Process( Bar & data ) {/*код обработки*/} ............ };
|
я пока что придумал примерно три решения
1) switch
| Код | void Dispatch(Context& ctx, id_t id, buf_t& buf) { switch(id) { default: assert(!"unknown id"); Foo::id : ctx.Process( Foo(buf) ); Bar::id : ctx.Process( Bar(buf) ); } }
|
2) саморегистрирующиеся фабрики
| Код | template<class Context> struct Register { template<class Processee> static bool Reg() { Map()[Processee::id] = &StartProcess<Processee>; return true; }
typedef void(*StartProcess_t)(Context& ctx, buf_t& buf); template<class Processee> static void StartProcess(Context& ctx, buf_t& buf) { ctx.Process( Processee(buf) ); }
typedef std::map<id_t,StartProcess_t> map_t; static map_t& Map() { static map_t map_; return map_; } }; template<class Context> void Dispatch(Context& ctx, id_t id, buf_t& buf) { Register<Context>::map_t map_=Register<Context>::Map(); assert( map_.find(id) != map_.end() && "unknown id" ); (map_[id])(ctx,buf); }
#define REGISTER(name) \ struct Context; \ struct name; \ namespace trash{ bool BOOST_PP_CAT(reg,__LINE__) = Register<Context>::Reg<name>(); } \ struct name \ /*******************/
REGISTER(Foo) { static const int id = 1; Foo(buf_t){/*...*/} /*...*/ };
REGISTER(Bar) { static const int id = 2; Bar(buf_t){/*...*/} /*...*/ };
|
в этом варианте добавлять новые структуры удобно, все сосредоточенно в одном месте
3) списки типов
| Код | template<typename AccepteesList> void Dispatch(Context& ctx, id_t id, buf_t& buf) { typedef boost::mpl::front<PacketsListTail>::type current_t; if( current_t::id == id ) return ctx.Process( current_t(buf) );
Dispatch<boost::mpl::pop_front<AccepteesList>::type>(ctx,id,buf); } template<> void Dispatch<boost::mpl::list<>::type>(Context&, id_t, buf_t&) { assert(!"unknown id"); }
.................. /* запуск Dispatch */ Dispatch<boost::mpl::list<Foo,Bar>::type>(ctx,id,buf);
|
Какие еще могут быть варианты? |