OK, I edited my original approach and added some more items to the list of mechanisms this can (should?) be applied to. I've worked out the concept for this mechanism a little more and I'll write more on it later. In essence, I'm saying that we can create an object that will specify rather a function call should be used to get or set the values or if we can just manipulate it directly in memory. This should reduce the overhead of function calls, as well as the generation of getter & setter functions in the object code, that the compiler will normally not generate for in-lined functions, while also facilitating access to values that require getter & setter calls (e.g., values that shouldn't be accessed asynchronously, etc.). I like a lot of how Boost.Serialization works, but I just can't buy into everything they do. So I'm thinking we can have a small macro:
#define GAE_ATTRIBUTE(field, getter, setter, flags) // some definition
The only real reason for the macro is to be able to stringize the field name, like we're doing in STRINGY_ENUM. So then a template<class ObjectType> AttributeManager (or we could call it ObjectSerializer, or whatever) that will serialize & deserialize objects of type Unit could be defined something like this:
class UnitSerializer : public AttributeManager<Game::Unit> {
public:
UnitSerializer();
};
UnitSerializer::UnitSerializer() {
GAE_ATTRIBUTE(id, NULL, NULL, 0); // don't use a getter or setter and no special flags
GAE_ATTRIBUTE(hp, NULL, setHp, 0); // directly access from memory for reads, but call setter for writes
GAE_ATTRIBUTE(ep, getEp, setHp, 0); // use both getter & setter
GAE_ATTRIBUTE(rotation, NULL, NULL, Attribute::NO_NETWORK); // don't send this across the network
// etc...
}
And actually, I'm wondering if this can be re-architected in such a fashion that we can simply add a single function like this to each class to further simplify it. Example:
class Unit {
// blah blah blah
public:
shared_ptr<AttributeManager<Unit> > getAttributeManager() {
shared_ptr<AttributeManager<Unit> > ret = shared_ptr<AttributeManager<Unit> >(new AttributeManager<Unit>);
ret->GAE_ATTRIBUTE(id, NULL, NULL, 0);
ret->GAE_ATTRIBUTE(hp, NULL, setHp, 0);
// etc...
}
};
Anyway, the point is to keep it as simple, easy to implement, succinct, type safe and error-proof as possible.