$include_dir="/home/hyper-archives/boost-users/include"; include("$include_dir/msg-header.inc") ?>
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://listarchives.boost.org/mailman/listinfo.cgi/boost-users
> >
>
>
> _______________________________________________
> Boost-users mailing list
> Boost-users_at_[hidden]
> http://listarchives.boost.org/mailman/listinfo.cgi/boost-users
>