Pointer to member-of-member???

S

Steve Rencontre

I can't for the life of me see how to do pointer-to-member when the
member is actually part of an embedded structure.

That is, if I have:

struct S1 { int a; };
struct S2 { S1 s; int b; };

how can I get a pointer to the a in an S2?

Obviously I can point at the b with

int S2:*p = &S2::b;

But the seemingly obvious syntax

int S2::*p = &S2::s.a;

doesn't work - because S2::s.a is not a /qualified-id/ - and neither
does anything else I can think of.

After all, if I have an S2 structure, there's absolutely no difference
from the compiler's POV between s2.s.a and s2.b, so why should I not be
able to have a construct s2.*p equivalent to the former case?

At the moment, the only thing I have found is a rather yucky workaround
with offsetof() macros and lots of casts. That is,

size_t offset = offsetof (S2, s.a);

*(int *) ((char *) &s2 + offset) = 123;

Ugh :-(((

Any better suggestions gratefully received!
 
R

red floyd

Steve said:
I can't for the life of me see how to do pointer-to-member when the
member is actually part of an embedded structure.

That is, if I have:

struct S1 { int a; };
struct S2 { S1 s; int b; };

how can I get a pointer to the a in an S2?

Obviously I can point at the b with

int S2:*p = &S2::b;

But the seemingly obvious syntax

int S2::*p = &S2::s.a;

void f()
{
int S1::*p = &S1::a;
S2 s2;

(s2.s).*a = 7; // parens because I can never remember .* precedence
}
 
B

Ben Pope

Steve said:
I can't for the life of me see how to do pointer-to-member when the
member is actually part of an embedded structure.

That is, if I have:

struct S1 { int a; };
struct S2 { S1 s; int b; };

how can I get a pointer to the a in an S2?

Well, a is an int, so what's wrong with an int*?
Obviously I can point at the b with

int S2:*p = &S2::b;

Can you?
But the seemingly obvious syntax

int S2::*p = &S2::s.a;

Not so obvious to me. There's aren't member functions.
doesn't work - because S2::s.a is not a /qualified-id/ - and neither
does anything else I can think of.

After all, if I have an S2 structure, there's absolutely no difference
from the compiler's POV between s2.s.a and s2.b, so why should I not be
able to have a construct s2.*p equivalent to the former case?

At the moment, the only thing I have found is a rather yucky workaround
with offsetof() macros and lots of casts. That is,

size_t offset = offsetof (S2, s.a);

*(int *) ((char *) &s2 + offset) = 123;

Ugh :-(((

Any better suggestions gratefully received!

What's wrong with:

int* s2s1a = &s2.s.a;

Ben Pope
 
I

Ian Collins

Steve said:
I can't for the life of me see how to do pointer-to-member when the
member is actually part of an embedded structure.

That is, if I have:

struct S1 { int a; };
struct S2 { S1 s; int b; };

how can I get a pointer to the a in an S2?

Obviously I can point at the b with

int S2:*p = &S2::b;
This isn't valid C++ syntax.
But the seemingly obvious syntax

int S2::*p = &S2::s.a;
?

Data members of a class/struct an only be accesses through an instance
of that object:

S2 s2;

int* p = &s2.s.a;

Are you confused with pointers to member functions?
 
J

John Carson

Ben Pope said:
Well, a is an int, so what's wrong with an int*?

If you have only one S1 object, then probably nothing. If you have 1,000,
then you would need 1,000 pointers. With a pointer to member, by contrast,
you only need one pointer to member.

Yes, he can.
Not so obvious to me. There's aren't member functions.

That particular syntax is wrong, but you can have pointers to data members,
just as you can have pointers to member functions. A pointer to member is
essentially an offset into the class, e.g.,

struct Foo
{
int x, y;
};

int Foo::*px = &Foo::x;
int Foo::*py = &Foo::y;

Now, given:

Foo f1;

you can use

f1.*px and f1.*py

in place of

f1.x and f1.y

respectively. More significantly, given:

Foo array[1000];

you can use

array.*px and array.*py

for i=0 to 999 in place of

array.x and array.y

respectively. What is the point? Suppose you wanted to swap the roles of x
and y (because, e.g., they represent coordinates and you are doing a
coordinate transformation). Then you just need to change the pointer
assignments to:

px = &Foo::y;
py = &Foo::x;

and now

array.*px will affect the y value and array.*py will affect the x
value.
 
S

Steve Rencontre

red said:
void f()
{
int S1::*p = &S1::a;
S2 s2;

(s2.s).*a = 7; // parens because I can never remember .* precedence
}

Thanks, but that's not what I want. I want a pointer to an int
/somewhere/ in S2, not one that makes me specify exactly what bit of S2
it's in.
 
S

Steve Rencontre

Ian said:
This isn't valid C++ syntax.

Whoops, missing ':'

int S2::*p = &S2::b;

But with that typo fixed, it's definitely proper C++.
Are you confused with pointers to member functions?

Pointers to data members are perfectly valid. In any case, the same
problem applies with pointers to function members. IOW, if I replaced
the declarations 'int a' and 'int b' with 'int a()' and 'int b()',
there'd still be no obvious way of specifying a pointer to member a;
 
J

John Carson

Steve Rencontre said:
Thanks, but that's not what I want. I want a pointer to an int
/somewhere/ in S2, not one that makes me specify exactly what bit of
S2 it's in.


Then I believe you are out of luck. You only get that sort of flexibility
with a regular pointer, not with a pointer to member.
 
I

Ian Collins

Steve said:
Thanks, but that's not what I want. I want a pointer to an int
/somewhere/ in S2, not one that makes me specify exactly what bit of S2
it's in.

That doesn't make sense, poners point to exact things.
 
J

John Carson

Ian Collins said:
It is when the member is an int.

A data member that is an int can be pointed to in two ways: by a regular
pointer to int and by a pointer to a member int. You don't seem to believe
in the existence of the second category of pointers. They do exist
nevertheless. See my reply to Ben Pope.
 
J

John Carson

Ian Collins said:
That doesn't make sense, poners point to exact things.

It does make sense. You can define

int * ptr;

and make it point to any int (only one int at a time, of course).

In a similar way, Steve wants a pointer to member int that can be made to
point to many different int members, although only one at a time. Alas, he
wants it to be able to point to both direct members and indirect members
(i.e., members of members). This is not possible, as far as I know.
 
I

Ian Collins

John said:
A data member that is an int can be pointed to in two ways: by a regular
pointer to int and by a pointer to a member int. You don't seem to believe
in the existence of the second category of pointers. They do exist
nevertheless. See my reply to Ben Pope.
Oh I do, I was just a little confused by the question....
 
G

Greg

Steve said:
I can't for the life of me see how to do pointer-to-member when the
member is actually part of an embedded structure.

That is, if I have:

struct S1 { int a; };
struct S2 { S1 s; int b; };

how can I get a pointer to the a in an S2?

You can't. In order to have a pointer to a member, the pointer must be
to a member of the class designated by the pointer. Since a is a member
of S1, and not a member of S2, it can only be designated with an S1
pointer-to-member variable.

It is however possible to to apply two member pointers, one S2 member
pointer and one S1 member pointer to specify an int member of an S1
struct that is a data member of an S2 struct. For instance, declaring:

S1 S2::*p1;
int S1::*p2;

and then initializing both appropriately (for example, p1 = &S1::s; p2
= &S2::a) makes it possible to reach S1's "a" data member from an S2
struct by applying p1 to an instance of an S2 struct, and then applying
p2 to the result of that operation.

Greg
 
B

Ben Pope

John said:
struct Foo
{
int x, y;
};

int Foo::*px = &Foo::x;
int Foo::*py = &Foo::y;

Now, given:

Foo f1;

you can use

f1.*px and f1.*py

in place of

f1.x and f1.y

respectively. More significantly, given:

Foo array[1000];

you can use

array.*px and array.*py

for i=0 to 999 in place of

array.x and array.y

respectively. What is the point? Suppose you wanted to swap the roles of x
and y (because, e.g., they represent coordinates and you are doing a
coordinate transformation). Then you just need to change the pointer
assignments to:

px = &Foo::y;
py = &Foo::x;

and now

array.*px will affect the y value and array.*py will affect the x
value.


That's cunning, I like it.

Thanks for the explanation and example. Not something you see every day
(not for me, anyway!).

Ben Pope
 
S

Steve Rencontre

Greg said:
You can't.

So I gather...
In order to have a pointer to a member, the pointer must be
to a member of the class designated by the pointer. Since a is a member
of S1, and not a member of S2, it can only be designated with an S1
pointer-to-member variable.

Well, yes, but that seems to me an arbitrary limitation. Although a is
not a member of S2, I contend that s.a is, the only problem being the .
operator which is not allowed in a /qualified-name/.

Since the thing with offsetof() and casts works perfectly well and is
completely portable, I am a bit frustrated I can't do it with a decent
syntax.
It is however possible to to apply two member pointers

Yuk. Sorry.

But as it happens, this is now all a bit academic. I've managed to
rearrange the code in question so that it now decides which member to
point to /after/ it gets the actual object reference, which means I can
just use a straight int *. I still wish it were possible, though,
because it would be slightly more elegant that way. (Although it's still
better than the hideous offsetof() bodge!)
 
R

Rolf Magnus

Steve said:
So I gather...


Well, yes, but that seems to me an arbitrary limitation. Although a is
not a member of S2, I contend that s.a is, the only problem being the .
operator which is not allowed in a /qualified-name/.

Because that operator is for accessing _objects_ only. It can't be applied
to types. It's not just a limitation of the syntax.

An int S2::* can only point to int members of S2. S1 is a different
structure, and S1::a is obviously not a member of S2, so if you want to
point to an int member of S1 (no matter where the actual object you want to
acces lives), you need an int S1::*.
There is no such thing as "members of members". That's because on one side,
you're talking about types, on the other side there are objects. While S1
and S2 are types, S2::s is not.
Yuk. Sorry.

Well, you can wrap that into a class (or even a class template) that does
what you want.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,226
Members
46,815
Latest member
treekmostly22

Latest Threads

Top