I’m a vegetarian, so suppose we have vegetables:
class Vegetable {}; // base class for vegetables
class Tomato : public Vegetable {};
class Potato : public Vegetable {};
class Carrot : public Vegetable {};
class Broccoli : public Vegetable {};
And suppose we wanna make meals with them:
class Meal {}; // base class for meals
class Soup : public Meal {
...
Soup(Vegetable *veg1, Vegetable *veg2) : veg1(veg1), veg2(veg2) {};
};
class Salad : public Meal {
...
Salad(Vegetable *veg1, Vegetable *veg2, Vegetable *veg3) : veg1(veg1), veg2(veg2), veg3(veg3) {};
};
class VeggieBurger : public Meal {
...
VeggieBurger(Vegetable *veg) : veg(veg) {};
};
Now we’d like to define different meals with different vegetable combinations in a cookbook:
std::vector<Meal *> cookbook;
cookbook.push_back(new Soup(new Tomato, new Potato));
cookbook.push_back(new Soup(new Potato, new Broccoli));
cookbook.push_back(new Salad(new Tomato, new Carrot, new Broccoli));
cookbook.push_back(new Salad(new Tomato, new Potato, new Tomato));
cookbook.push_back(new Salad(new Broccoli, new Potato, new Carrot));
cookbook.push_back(new VeggieBurger(new Potato));
// many more meals...
So we are creating many little objects on the heap that are getting composed together via constructor arguments and pushed onto a std::vector at runtime. Obviously the downside of this design is, that we have to manage the memory ourselves and delete the Vegetable objects in our meals destructor and delete our cookbook meals somewhere when it goes out of scope.
So a possible design choice would be to use smart pointers to out source the burden of doing memory management for our meals and vegetables.
But I’m wondering if it is possible to compose the cookbook at compile time, maybe with some kind of template magic? The cookbook does not necessarily have to be a std::vector but we still like to be able to iterate over it, get the Meal objects and call member functions on a composed meal. Are there better ways to do it?
I’ve found that code generation is becoming an incredibly useful tool for me. Maybe write a short program, perhaps even just a script, than will generate the boilerplate code for you.
Any time you add to your cookbook, you run the program/script, which will generate the headers for each meal and the header, maybe even some of the source, for the cookbook itself.
How in-depth you get with your generation is up to you. You could just edit the code generator’s source to add new meals, you could do some simple text based parsing, or, if it’s really worth the time and effort to maintain, turn your code generator into an editor (with code generation as its output).
At least one very well know AAA game engine actually generates C++ header files for any scripts that are marked to interface with native code. From there, a macro in a source file implements the boilerplate methods. The rest of the methods are implemented by the developers.
Update:
C++11 actually has support for variadic template arguments. I don’t have any experience with C++11, so I’m not sure if variadic template arguments would support what we’re looking at.