c++ - Code generation with macros: Class with members and constructor -
let's want define classes of following structure:
struct myclass { int x; bool y; float z; myclass(qvariantmap data) : x(data["x"]), y(data["y"]), z(data["z"]) {} };
as can see, have qvariantmap (something similar std::map<std::string, boost::variant<...>>
of not familiar qt) want able construct such type no further knowledge of fields, hence convenient constructor should "deserialize" fields map.
i need several classes of style, , want definitions clean possible maximum maintainability (regarding typos in string keys), readability , automation.
i thought of macro structure following:
def_class(myclass)( def_field(int, x) def_field(bool, y) def_field(float, z) );
i don't see problem when want generate fields not constructor (the other way around possible, i'll demonstrate former only):
#define def_class(classname) \ struct classname { \ _def_class_tail/*..."curry arguments"...*/ #define _def_class_tail(fields) \ fields \ } #define def_field(type, name) type name;
i define first macro starts class definition , use "curry" technique forward second parentheses second macro puts contents of class definition (fields
) , closes afterwards. way -- idea -- have access fields
within second macro.
but how can output fields twice, 1 define actual fields , 1 output member initialization?
i know if define macro def_class_field
in 2 different ways , "include" fields definition code above, 1 every macro definition, print them 1 after correctly. since field listing (and should) within class definition, cannot include twice.
are there other options?
i try avoid boost preprocessor library, if have nice solution uses that, go ahead. however, prefer simple solution, if there any.
here example not build struct cache values map, checks @ constructor map contains fields, discussed in comments of opening question.
#define def_class(classname) \ struct classname { \ classname(qvariantmap& map) {\ _def_class_tail/*..."curry arguments"...*/ #define _def_class_tail(fields) \ fields \ }}; #define chk_field(type, name) \ if (typeid(type)!=typeid(map[#name])) \ { throw std::runtime_error(#name" missing or wrong type");} def_class(myclass)( chk_field(int, x) chk_field(bool, y) chk_field(float, z) );
this produces following preprocessor (after running through astyle):
struct myclass { myclass(qvariantmap& map) { if (typeid(int) != typeid(map["x"])) { throw std::runtime_error("x"" missing or wrong type"); } if (typeid(bool) != typeid(map["y"])) { throw std::runtime_error("y"" missing or wrong type"); } if (typeid(float) != typeid(map["z"])) { throw std::runtime_error("z"" missing or wrong type"); } } };
edit: i'm not 100% sure typeid comparisons work this, should straight forward replace check work.
Comments
Post a Comment