banging my head on the c++, again
Sep. 2nd, 2008 08:02 pmIs 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?
no subject
Date: 2008-09-03 03:26 am (UTC)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.
no subject
Date: 2008-09-03 04:32 am (UTC)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,
fmight return the value ofs.aors.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).no subject
Date: 2008-09-03 04:33 am (UTC)no subject
Date: 2008-09-03 04:43 am (UTC)no subject
Date: 2008-09-03 09:35 pm (UTC)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.no subject
Date: 2008-09-03 10:24 pm (UTC)no subject
Date: 2008-09-03 06:48 am (UTC)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.
no subject
Date: 2008-09-03 10:26 pm (UTC)no subject
Date: 2008-09-03 02:24 pm (UTC)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.
no subject
Date: 2008-09-03 10:30 pm (UTC)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...