Некоторое время назад я задумывался об авто генерации классов, тогда я хотел использовать xml+xslt для того чтобы генерировать описания и загрузчики объектов интерфейса. Недавно я снова вернулся к этой идее и понял что использовать связку xml+xslt очень геморно, в связи с особенностями xslt. Если делаешь однопроходный парсинг то xml файл получается очень нагроможденным. Помучившись около часа я плюнул на эту затею и начал писать код на C++. В результате за несколько часов было написано около 600 строк кода и теперь у меня есть весьма неплохой генератор.
Из вот такого файла:
[object]
name Timer
[includes]
[include0]
file me_time.h
[/]
[include1]
file me_signal.h
[/]
[/]
[base]
[base_class0]
name SceneObject
inheritance public
[/]
[/]
[public]
[functions]
[function0]
name load
type builtin
define yes
parents_ok all
[/]
[function1]
name draw
type builtin
define no
[/]
[function2]
name constructor
type builtin
define yes
[/]
[function3]
name destructor
type builtin
define yes
[/]
[/]
[slots]
[slot0]
name _on_new_cycle
[/]
[/]
[/]
[input_params]
[param0]
name repeat
type bool
[/]
[param1]
name time
type float
default 1.0
[/]
[/]
[protected]
[variables]
[variable0]
name timer
type Time
[/]
[/]
[signals]
[signal0]
name time_out
[signal_params]
[param0]
name dt
type float
[/]
[/]
[/]
[/]
[/]
[/]Генерируется вот такой вот исходник:
#pragma once #include <string> #include "sceneobjectfabric.h" #include "me_time.h" #include "me_signal.h" #include "sceneobject.h" class Timer : virtual public SceneObject { public: //public slots DECLARE_SLOT(Timer, _on_new_cycle ) { return _on_new_cycle_handler(); } bool _on_new_cycle_handler(); //public functions bool load ( std::string storage_name, std::string storage_prefix, std::string scene_name, std::string object_name, FileIO::FileManager *fmanager) { Config_Interface *intf = config_get_interface ( storage_name ); if ( !intf ) { _set_error ( "Can't get config interface:" + config_error() ); return false; } bool state[1]; state[0]=SceneObject::load(storage_name, storage_prefix, scene_name, object_name, fmanager); for(int a=0;a<1; ++a) if(!state[a])return false; repeat = (intf->_get_value(storage_prefix+"Timer->repeat", "")=="true")?true:false; time = atof(intf->_get_value(storage_prefix+"Timer->time", "1.0").c_str()); _slot_map_.push_back( std::make_pair(_scene_name_ + "->" + _object_name_ + "->_on_new_cycle", &_on_new_cycle)); return real_load(storage_name, storage_prefix, scene_name, object_name, fmanager); } bool real_load ( std::string storage_name, std::string storage_prefix, std::string scene_name, std::string object_name, FileIO::FileManager *fmanager); void draw(); Timer () : SceneObject(), INIT_SLOT(Timer, this, _on_new_cycle ){} ~Timer(){} //public signals protected: //protected slots //protected functions //protected signals Signal time_out; void rise_time_out( float dt) { time_out.clear_params(); time_out.add_params(dt); time_out.rise(); } private: //private slots //private functions //private signals public: //public variables // loadable params bool repeat; float time; protected: //protected variables Time timer; private: //private variables }; extern ObjectFabric<Timer> TimerFabric;
Таким образом сразу генерируются функции загрузки и отображения объекта (по требованию), генерируются врапперы для сигналов и слотов, которые работают с понятными параметрами а не с args->int_args, что очень сильно помогает упростить жизнь)
Благодаря такому подходу достаточно легким становится написание редактора интерфейса, который будет парсить данный файл и узнавать список параметров.
Также раньше всплывала проблема сложности определения входных параметров каждого объекта, однако при наличии файла описание всегда есть где посмотреть не ковыряясь в куче кода.
В общем один профит)
Leave a reply