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
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
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
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
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
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
(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
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
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