Let's say I want to define classes of the following structure:
struct MyClass {
int x;
bool y;
float z;
MyClass(QVariantMap data) : x(data["x"]), y(data["y"]), z(data["z"]) {}
};
As you can see, I have a QVariantMap (something similar to std::map<std::string, boost::variant<...>> for those of you not familiar with Qt) from which I want to be able to construct such a type with no further knowledge of its fields, hence the convenient constructor which should "deserialize" the fields from the map.
I need several classes of this style, and I want the definitions to be as clean as possible for maximum maintainability (regarding typos in the string keys), readability and automation.
I thought of a macro structure like the following:
DEF_CLASS(MyClass)(
DEF_FIELD(int, x)
DEF_FIELD(bool, y)
DEF_FIELD(float, z)
);
I don't see any problem when I only want to generate the fields but not the constructor (the other way around is also possible, but I'll demonstrate the former only):
#define DEF_CLASS(CLASSNAME) \
struct CLASSNAME { \
_DEF_CLASS_TAIL/*..."curry the arguments"...*/
#define _DEF_CLASS_TAIL(FIELDS) \
FIELDS \
}
#define DEF_FIELD(TYPE, NAME) TYPE NAME;
I define the first macro which starts the class definition and use a "curry" technique to forward the second parentheses to a second macro which puts the contents of the class definition (FIELDS) and closes it afterwards. This way -- so was my idea -- I have access to the FIELDS within the second macro.
But how can I now output the fields twice, one to define the actual fields and one to output the member initialization?
I know that if I define the macro DEF_CLASS_FIELD in two different ways and then somewhat "include" the fields from my definition code above, one for every macro definition, I could print them one after another correctly. But since the field listing is (and should) be within the class definition, I cannot simply include something twice.
Are there other options?
I try to avoid the Boost preprocessor library, but if you have a nice solution which uses that, go ahead. However, I very much prefer a simple solution, if there is any.
#xto generate"x") and a type, and then performs the check:if (typeid(map[KEY])!=typeid(TYPE)) { throw; }?