
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

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

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

AMDG Joseph Fradley 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);
You could try something along these lines: class indexable_base { public: virtual indexable_base* lookup(const char*) = 0; virtual const std::type_info& get_type() = 0; virtual void* get() = 0; }; Then you can put macros in the derived class like so: class Rectangle : public indexable_base { DEFINE_LOOKUP() { DECLARE_VARIABLE(corner); } Point Corner; }; Which would expand to something like class Rectangle : public indexable_base { template<class T> void getMemberValue(const char* key, T& out) { indexable_base result = lookup(key); if(typeid(T) == result->get_type()) { out = *(static_cast<T*>(result->get())) } else { throw(std::bad_cast()); } } indexable_base* lookup(const char* key) { // split key at ":" and lookup call lookup_ recursively until all the keys are used up. } static void init() { map_.insert(std::make_pair("corner", &boost::bind(&Rectangle::corner, _1))); } Point corner; }; In Christ, Steven Watanabe

Joseph Fradley 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);
Steven Watanabe wrote:
You could try something along these lines:
class indexable_base { public: virtual indexable_base* lookup(const char*) = 0; virtual const std::type_info& get_type() = 0; virtual void* get() = 0; };
Then you can put macros in the derived class like so:
class Rectangle : public indexable_base { DEFINE_LOOKUP() { DECLARE_VARIABLE(corner); } Point Corner; };
Which would expand to something like
class Rectangle : public indexable_base { template<class T> void getMemberValue(const char* key, T& out) { indexable_base result = lookup(key); if(typeid(T) == result->get_type()) { out = *(static_cast<T*>(result->get())) } else { throw(std::bad_cast()); } } indexable_base* lookup(const char* key) { // split key at ":" and lookup call lookup_ recursively until all the keys are used up. } static void init() { map_.insert(std::make_pair("corner", &boost::bind(&Rectangle::corner, _1))); } Point corner; };
Steven, Thank you, I'm trying it now. But I'm a confused as to what type of map to create from your line : map_.insert(std::make_pair("corner", &boost::bind(&Rectangle::corner, _1))); I've just now read up on boost::bind and I can only see documentation of binding to member functions not member data. Could you elaborate? Joe

AMDG Joseph Fradley wrote:
Steven,
Thank you, I'm trying it now. But I'm a confused as to what type of map to create from your line : map_.insert(std::make_pair("corner", &boost::bind(&Rectangle::corner, _1)));
I've just now read up on boost::bind and I can only see documentation of binding to member functions not member data. Could you elaborate?
Joe
boost::function<Point&(Rectangle*)> f = boost::bind(&Rectangle::corner, _1); Rectangle rect; Point p = f(&rect); // equivalent to p = f.corner; In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
Joseph Fradley wrote:
Steven,
Thank you, I'm trying it now. But I'm a confused as to what type of map to create from your line : map_.insert(std::make_pair("corner", &boost::bind(&Rectangle::corner, _1)));
I've just now read up on boost::bind and I can only see documentation of binding to member functions not member data. Could you elaborate?
Joe
boost::function<Point&(Rectangle*)> f = boost::bind(&Rectangle::corner, _1);
Rectangle rect;
Point p = f(&rect); // equivalent to p = f.corner;
I think you meant: // equivalent to rect.corner Jeff Flinn
participants (4)
-
Jeff Flinn
-
Joseph Fradley
-
Ovanes Markarian
-
Steven Watanabe