zwol: stylized sketch of a face in profile (Default)
[personal profile] zwol

Is it possible in C++ to declare and initialize a pointer-to-member that points to a data member of a data member? Concretely, given

struct A { int x; int y; };
struct B { A i; A ii; A iii; A iv; };

I would like to be able to do something like this:

TYPE piix = INITIALIZER<B, ii, x>;
...
B b;
int x_within_ii = b.*piix;

Is this possible? If so, exactly how do you write TYPE and INITIALIZER? If not, why the hell not?

Date: 2008-09-03 03:26 am (UTC)
From: [identity profile] marphod.livejournal.com
Uh. Hunh?

I'm totally confused what you want to do.

First, the type of i.x is just an int. if you want a pointer to it is simply
int* piix = &(b.ii.x); // and I believe the parens are optional.

Although, in this example, B should be
struct B { A i[4]; }; // unless you have a good reason

so that's be
int* i = &(b.i[1].x);

Pointers to data members aren't particularly exciting. They're just pointers to stack or heap objects. Pointers to member methods are interesting, as you need to cope with the this object; Plain old data is just plain old data is just plain old data.

Date: 2008-09-03 04:32 am (UTC)
From: [identity profile] zwol.livejournal.com

Er, you (like almost everyone on the net, it seems) have missed the subtle distinction between a pointer and a pointer-to-member. They're not at all the same thing. You can take a pointer-to-member without having access to an instance. Canonical usage is something like

struct S { int a; int b; };

int f(S & s, S::*int which) 
{ 
  return s.*which;
}

Depending how it's called, f might return the value of s.a or s.b. In the actual code that motivates the question, I have an array of pointers-to-members, one for each of the members, so I can loop over the contents of an object (yes, there is a compelling reason not to use an array object in the first place).

Date: 2008-09-03 04:33 am (UTC)
ext_3729: All six issues-to-date of GUD Magazine. (Default)
From: [identity profile] kaolinfire.livejournal.com
I learn more about c++ from your questions ...

Date: 2008-09-03 04:43 am (UTC)
From: [identity profile] zwol.livejournal.com
Glad to be doing someone some good here...

Date: 2008-09-03 09:35 pm (UTC)
From: [identity profile] marphod.livejournal.com
Aaaah.

No. There is no way, as there is no way to give a pointer a this pointer, in order to resolve it.


Now, there are ways around this.

You can make an offset table. Create an exmplar object of the desired type, and do
struct S{ int a; int b; };
S obj; // implicit default ctor
int offsets[] = { reinterpret_cast<int>(
                    (&dynamic_cast<S>(obj.a) - &dynamic_cast<S>(obj)),
                  reinterpret_cast<int>(
                    (&dynamic_cast<S>(obj.b) - &dynamic_cast<S>(obj))
                };

S obj2(foo, bar, baz, qux);
assert(&obj2.a == (&obj2 + offset[0]);
assert(&obj2.b == (&obj2 + offset[1]);
assert(obj2.a == (int)(*(int*)(&obj2 + offset[0])); // get lazy, I know.

Make a quick templated functor, and this can look cleaner.  Regardless it should work.

Date: 2008-09-03 10:24 pm (UTC)
From: [identity profile] zwol.livejournal.com
This is not helpful; you clearly still have no point of reference for my original question, and your suggestions are no good. [livejournal.com profile] falsedrow gave the answer I needed, so please just stop.

Date: 2008-09-03 06:48 am (UTC)
From: [identity profile] elsmi.livejournal.com
std::pair
[Error: Irreparable invalid markup ('<b::*a,>') in entry. Owner must fix manually. Raw contents below.]

std::pair<B::*A, A::*int>?

I guess they could have provided B::*A::*int as sugar for something like this, but glancing at C++98 I don't think they did. If everything's POD then you can use offsets, which do compose, I guess.

Date: 2008-09-03 10:26 pm (UTC)
From: [identity profile] zwol.livejournal.com
geh, I suppose ... not really tidier than a helper function or something.

Date: 2008-09-03 02:24 pm (UTC)
From: [identity profile] falsedrow.livejournal.com
It's not possible. If it were, I presume it would look like this:

int B::* piix = &B::ii.x;
B b;
int x_within_ii = b.*piix;

But ii is not allowed in INITIALIZER so you're out of luck. I'm guessing it would just have complicated the grammar too much; &B::ii is a qualified-id and those are supposed to refer to direct members of the qualifying scope. I don't know if it would parse as "&B::ii" . "x" or & "B::ii.x", for one thing.

Date: 2008-09-03 10:30 pm (UTC)
From: [identity profile] zwol.livejournal.com
Drat, I was afraid that was what it came down to.

GCC's error messages for this could be improved - "invalid use of non-static data member B::ii" leaves the possibility open that if you just wrote either the type or the initializer slightly differently it would be valid...

April 2017

S M T W T F S
      1
2345678
9101112131415
16171819 202122
23242526272829
30      

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 3rd, 2026 04:24 am
Powered by Dreamwidth Studios