tags:

views:

249

answers:

4

I had the following piece of code (simplified for this question):

struct StyleInfo
{
    int width;
    int height;
};

typedef int (StyleInfo::*StyleInfoMember);

void AddStyleInfoMembers(std::vector<StyleInfoMember>& members)
{
    members.push_back(&StyleInfo::width);
    members.push_back(&StyleInfo::height);
}

Now, we had to restructure this a bit, and we did something like this:

struct Rectangle
{
    int width;
    int height;
};

struct StyleInfo
{
    Rectangle size;
};

typedef int (StyleInfo::*StyleInfoMember);

void AddStyleInfoMembers(std::vector<StyleInfoMember>& members)
{
    members.push_back(&StyleInfo::size::width);
    members.push_back(&StyleInfo::size::height);
}

If this all looks like a stupid thing to do, or if you feel there's a good opportunity to apply BOOST here for some reason, I must warn you that I really simplified it all down to the problem at hand:

error C3083: 'size': the symbol to the left of a '::' must be a type

The point I'm trying to make is that I don't know what the correct syntax is to use here. It might be that "StyleInfo" is not the correct type of take the address from to begin with, but in my project I can fix that sort of thing (there's a whole framework there). I simply don't know how to point to this member-within-a-member.

A: 

Well, this isn't an answer to your question, but have you considered the law of demeter in the design?

Josh
I think you mean demeter.
Simon Howard
Thanks, I should double check my typing.
Josh
Well yes, I'm considering doing that to my design. But there are implications that I thought I could circumvent here.
Dave Van den Eynde
+1  A: 

Is it definitely possible? I honestly don't know, never having played much with pointer-to-member.

Suppose you were using non-POD types (I know you aren't, but the syntax would have to support it). Then pointer-to-member might have to encapsulate more than just an offset from the base pointer. There might be indirection as well, depending how multiple inheritance is implemented. With multiple levels of member indirection, this could get arbitrarily complicated, which is a lot to ask for a type that has to have fixed size.

Perhaps you need a vector of pairs, of types defined by:

typedef Rectangle (StyleInfo::*StyleInfoMember);
typedef int (Rectangle::*RectangleMember);

Apply each in turn to get where you want to be. Of course this still doesn't let you build a vector of mappings from a StyleInfo to arbitrary members-of-members-of StyleInfo, since they wouldn't all go through Rectangle. For that you may need to open a can of functors...

Steve Jessop
I'm about to concede and bite the bullet and argue that it is indeed not possible. Sure, it's all POD types and the compiler will collapse them all into simple offsets to use when accessing those members. But that doesn't mean there's a way to do it properly other what you are suggesting.
Dave Van den Eynde
A: 

size (as in &StyleInfo::size::width) is not the name of a type.

try size->width or size.width instead, depending on how your 'AddStyleInfoMembers` knows about size at all.

andreas buykx
+2  A: 

Remember a pointer to a member is just used like a member.

 Obj x;

 int  y = (x.*)ptrMem;

But like normal members you can not access members of subclasses using the member access mechanism. So what you need to do is access it like you would access a member of the object (in your case via the size member).

#include <vector>
#include <iostream>


struct Rectangle
{
    int width;
    int height;
};

struct StyleInfo
{
    Rectangle size;
};

typedef Rectangle   (StyleInfo::*StyleInfoMember);
typedef int         (Rectangle::*RectangleMember);

typedef std::pair<StyleInfoMember,RectangleMember>  Access;

void AddStyleInfoMembers(std::vector<Access>& members)
{
    members.push_back(std::make_pair(&StyleInfo::size,&Rectangle::width));
    members.push_back(std::make_pair(&StyleInfo::size,&Rectangle::height));
}


int main()
{
    std::vector<Access>     data;
    AddStyleInfoMembers(data);

    StyleInfo       obj;
    obj.size.width  = 10;

    std::cout << obj.*(data[0].first).*(data[0].second) << std::endl;
}

This is not something I would recommend doing!

An alternative (that I recommend even less) is to find the byte offset from the beginning of the class and then just add this to the objects address. Obviously this will involve a lot of casting backwards and forwards so this looks even worse then the above.

Martin York