
Ovanes, That's pretty neat, I never knew you could do that. But I don't think it gets me there. If I'm coming in with an unknown const char *, I can get the extern equivalent via looping through a global registry doing strcmp()s. But once I get my index into the registry I can't place it into the template specification ( such as "TypeId<typeid_registry[i]> v;"). Also I was hoping to create all the required stuff via a single MACRO per class member, for example I was hoping to create something like this: class Point { getMemberValue() { INDEX_MACRO(x) INDEX_MACRO(y) } int x; int y; } Using the templated TypeId struct I have to define a whole lot of extern's out of the class and function declarations inside the class for each member. And probably the toughest problem with this, how to create a simple way to "expand the tree" of all possible access() functions. For example, if I'm coming in with an index of "corner:x" into Rectangle object, I don't want to know about a Point just an int. So, I would need a special type just for "corner:x" and a access() function that takes this type and return a int. In case you're interested below is what I came up with (minus the MACROs and minus it being able to compile). Thanks for you help, I probably have to think of a different solution. template<const char*> struct TypeId {}; ///header // for Point extern const char x[] = "x"; extern const char y[] = "y"; typedef TypeId<x> x_Accessor; typedef TypeId<y> y_Accessor; // for Rectangle extern const char corner[] = "corner"; extern const char width[] = "width"; extern const char height[] = "height"; typedef TypeId<corner> corner_Accessor; typedef TypeId<width> width_Accessor; typedef TypeId<height> height_Accessor; extern const char corner_x[] = "corner:x"; extern const char corner_y[] = "corner:y"; typedef TypeId<corner_x> corner_x_Accessor; typedef TypeId<corner_y> corner_y_Accessor; extern const char *typeid_registry[] = { x, y, corner, width, height, corner_x, corner_y, NULL }; struct PointClass { // get int access(x_Accessor) { return x; } int access(y_Accessor) { return y; } // set void set(x_Accessor, int value) { x = value; } void set(y_Accessor, int value) { y = value; } int x; int y; }; struct RectangleClass { // get int access(width_Accessor) { return width; } int access(height_Accessor) { return height; } PointClass access(corner_Accessor) { return corner; } int access(corner_x_Accessor) { return corner.x; } int access(corner_y_Accessor) { return corner.y; } // set void set(width_Accessor, int value) { width = value; } void set(height_Accessor, int value) { height = value; } void set(corner_Accessor, PointClass value) { corner = value; } void set(corner_x_Accessor, int value) { corner.x = value; } void set(corner_y_Accessor, int value) { corner.y = value; } int width; int height; PointClass corner; }; struct BlobClass { // a whole lot of access()/set() functions RectangleClass boundingBox; int centroid; float mass; }; int main(void) { RectangleClass rc; rc.corner.x = 55; rc.corner.y = 66; rc.width = 77; rc.height = 88; std::string simpleSrcKey = "width"; std::string simpleDestKey = "corner:x"; for(int srci = 0; typeid_registry[srci] != NULL; ++srci) { if(!strcmp(typeid_registry[srci], simpleSrcKey.c_str() )) { for(int dsti = 0; typeid_registry[dsti] != NULL; ++dsti) { if(!strcmp(typeid_registry[dsti], simpleDestKey.c_str() )) { TypeId<typeid_registry[0]> dst; TypeId<typeid_registry[0]> src; rc.set(dst, rc.access(src)); } } } } return 0; } On 1/29/08, Ovanes Markarian <om_boost@keywallet.com> wrote:
Yes, you can define your types based on const char* and overload template functions on them.
//using structs to skip explicit public access specifiers
///header extern const char SomeName[];
template<const char*> struct TypeId {};
typedef TypeId<SomeName> MemberX_Accessor;
struct ClassWithMembers { void access(MemberX_Accessor) { ... }
template<class T> void access(T) { /// issue error here, no accessor specified!!! }
private: MemberX x; };
///cpp extern const char SomeName[] ="memberX";
I hope that example brings you to some useful ideas.
Regards, Ovanes
On Jan 29, 2008 3:34 PM, Joseph Fradley <joe.fradley@fradeng.com> wrote:
I have a problem that I would like to solve in the most generic
non-intrusive way possible (such as boost serialization). What I want is to access class members both via it's initially designed accessors but also via a "const char *" key. In addition, I want to pass list of key's (via a vector of const char * or a single delimited multikey char *) to get nested member access.
For example: ... // these should be equivalent Point p; int val; val = p.x; val = p.getX(); p.getMemberValue("x", val);
// there also Rectangle r; int val; Point pVal; r.getMemberValue("corner:x", val); r.getMemberValue("corner", pVal);
I thought about having a templated function similar to the serialize()
function called 'getMemberValue()', where each 'if' block below could be wrapped into a MACRO taking just the member name.
template< class T > bool getMemberValue(const char *key, T & value) { if(!strcmp(key, "member")) { value = this->member; return true; } return false; }
This appears to work fine for one level deep but if I want the behavior
such as the above rectangle example, I run into trouble. I end up with a function implementation like this for the 'Rectangle' class
template< Point > bool getMemberValue(const char *key, Point & value) { if(!strcmp(key, "corner")) { value = this->corner; // Point return true; } if(!strcmp(key, "width")) { value = this->width; // int return true; } if(!strcmp(key, "height")) { value = this->height; // int return true; } return false; }
This fails because it ends up trying to set an integer value to a Point
variable.
Anybody have any suggestions?
Joe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users