Boost logo

Boost Users :

From: Joseph Fradley (joe.fradley_at_[hidden])
Date: 2008-01-29 11:46:37


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_at_[hidden]> 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_at_[hidden]> 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_at_[hidden]
> > http://lists.boost.org/mailman/listinfo.cgi/boost-users
> >
>
>
> _______________________________________________
> Boost-users mailing list
> Boost-users_at_[hidden]
> http://lists.boost.org/mailman/listinfo.cgi/boost-users
>


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net