pointer to a member of a member

H

huili80

Say I have two classes:

class A
{
public:
int x;
};

class B
{
public:
A a;
};

Then how do I construct a member pointer to B::a.x ? What's the syntax
for it?
Thanks!
 
N

n2xssvv.g02gfr12930

Say I have two classes:

class A
{
public:
int x;
};

class B
{
public:
A a;
};

Then how do I construct a member pointer to B::a.x ? What's the syntax
for it?
Thanks!

Not sure what you require, but the code sample below may be of help

int A::*ptr = A::x;
A Example;
Example.*ptr = 15;

JB
 
G

Greg Herlihy

Why do you think you need it?  Does this help:

     B b;
     int *ptr = &b.a.x;

The question seems to me to be asking for a member pointer - not a
pointer to a (data) member. If that is the case, then the answer would
be that it is not possible to create a single, member pointer to
b.a.x. Instead it is necessary to declare two member pointers (one for
B::a and the other for A::x) and then apply them both. For example:

struct A
{
int x;
};

struct B
{
A a;
};

int main()
{
B b;
A B::*pa = &B::a;
int A::*pi = &A::x;

b.*pa.*pi = 3; // assigns 3 to b.a.x
}

Greg
 
H

huili80

I would like to see what the OP has to say about his/her need to create
such a construct.

V

Here is an example (probably over-simplified from the actual case I'm
working on). Say I have a 2D vector class:

struct vector2d
{
double x,y;
static double vector2d::* const _v[2];
double& operator[] (int i) { return this->*_v; }
const double& operator[] (int i) const { return this->*_v; }
};
double vector2d::* const vector2d::_v[] = { &vector2d::x,
&vector2d::y };

and suppose we have an object "vector2d v;" . The purpose of using
pointer to member here is to make v[0] and v.x have exactly the same
run-time efficiency, provided that the compiler is capable of
necessary optimization. (I didn't invent this technique, but I forgot
where I learned it).

Suppose now for some reason, I want to build a 5D vector class out of
this 2D vector class, say like this.

class vector5d
{
vector2d v1, v2;
double z;
};

and we have an object "vector5d w;"

What I want is, with as little run-time overhead as possible (maybe
using a similar method that's used by vector2d), that w[0] gives me
w.v1.x , w[1] gives w.v1.y , w[2] gives w.v2.x , w[3] gives w.v2.y ,
and w[4] gives me w.z .

Is it possible? If yes, how?

Thanks!
 
H

huili80

I would like to see what the OP has to say about his/her need to create
such a construct.

Here is an example (probably over-simplified from the actual case I'm
working on). Say I have a 2D vector class:

struct vector2d
{
    double x,y;
    static double vector2d::* const _v[2];
    double& operator[] (int i) { return this->*_v; }
    const double& operator[] (int i) const { return this->*_v; }};

double vector2d::* const vector2d::_v[] = { &vector2d::x,
&vector2d::y };

and suppose we have an object "vector2d v;" . The purpose of using
pointer to member here is to make v[0] and v.x have exactly the same
run-time efficiency, provided that the compiler is capable of
necessary optimization. (I didn't invent this technique, but I forgot
where I learned it).

Suppose now for some reason, I want to build a 5D vector class out of
this 2D vector class, say like this.

class vector5d
{
    vector2d v1, v2;
    double z;

};

and we have an object "vector5d w;"

What I want is, with as little run-time overhead as possible (maybe
using a similar method that's used by vector2d), that w[0] gives me
w.v1.x , w[1] gives w.v1.y , w[2] gives w.v2.x , w[3] gives w.v2.y ,
and w[4] gives me w.z .

Is it possible? If yes, how?

I mean, is it possible to achieve zero run-time overhead (assuming
proper optimization) in accessing members (and their members) via an
index? If we don't have a vector5d::z (in which case it's actually a
4D vector), we might want to use an array of pointers to member of a
member (I don't know how even if they do exist). Having vector5d::z
makes this even more complicated in that a pointer to vector5d::z and
a (may or may not existing) pointer to vector5d::v1.x certainly would
have different types, so they cannot be put into an array.
 
H

huili80

Greg Herlihy wrote:
(e-mail address removed) wrote:
Say I have two classes:
class A
{
public:
    int x;
};
class B
{
public:
    A a;
};
Then how do I construct a member pointer to B::a.x ? What's the syntax
for it?
Why do you think you need it?  Does this help:
     B b;
     int *ptr = &b.a.x;
The question seems to me to be asking for a member pointer - not a
pointer to a (data) member. If that is the case, then the answer would
be that it is not possible to create a single, member pointer to
b.a.x. Instead it is necessary to declare two member pointers (one for
B::a and the other for A::x) and then apply them both. For example:
    struct A
    {
        int x;
    };
    struct B
    {
        A a;
    };
    int main()
    {
        B   b;
        A   B::*pa = &B::a;
        int A::*pi = &A::x;
        b.*pa.*pi = 3; // assigns 3 to b.a.x
    }
Greg
I would like to see what the OP has to say about his/her need to create
such a construct.
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Here is an example (probably over-simplified from the actual case I'm
working on). Say I have a 2D vector class:
struct vector2d
{
    double x,y;
    static double vector2d::* const _v[2];
    double& operator[] (int i) { return this->*_v; }
    const double& operator[] (int i) const { return this->*_v; }};
double vector2d::* const vector2d::_v[] = { &vector2d::x,
&vector2d::y };
and suppose we have an object "vector2d v;" . The purpose of using
pointer to member here is to make v[0] and v.x have exactly the same
run-time efficiency, provided that the compiler is capable of
necessary optimization. (I didn't invent this technique, but I forgot
where I learned it).
Suppose now for some reason, I want to build a 5D vector class out of
this 2D vector class, say like this.
class vector5d
{
    vector2d v1, v2;
    double z;
};
and we have an object "vector5d w;"
What I want is, with as little run-time overhead as possible (maybe
using a similar method that's used by vector2d), that w[0] gives me
w.v1.x , w[1] gives w.v1.y , w[2] gives w.v2.x , w[3] gives w.v2.y ,
and w[4] gives me w.z .
Is it possible? If yes, how?

I mean, is it possible to achieve zero run-time overhead (assuming
proper optimization) in accessing members (and their members) via an
index?  If we don't have a vector5d::z (in which case it's actually a
4D vector), we might want to use an array of pointers to member of a
member (I don't know how even if they do exist). Having vector5d::z
makes this even more complicated in that a pointer to vector5d::z and
a (may or may not existing) pointer to vector5d::v1.x certainly would
have different types, so they cannot be put into an array.


What you seem to be looking for is

     struct vector5d
     {
         vector2d v1, v2;
         double z;
         double& operator[](int i) {
             switch (i) {
                 case 0: return v1[0];
                 case 1: return v1[1];
                 case 2: return v2[0];
                 case 3: return v2[1];
                 case 4: return z;
                 default: throw "bad index";
             }
         }
     };

Isn't it?

V



That gives the correct result, but not the best performance. A more
efficient solution would be

switch(i/2)
{
case 0: return v1[i%2]; break;
case 1: return v2[i%2]; break;
case 2: return z; break;
default: throw "bad index";
}


because v1[k] (as implemented in my earlier post) is much faster than

if ( k == 0 )
return v1.x;
else
return v1.y;


But can we achieve even better efficiency? Directing the program to
different branch based on the even- or odd-ness of an integer would
almost certainly be slower than just shifting a pointer by that
integer. That's exactly how in the vector2d class, v[0] has the same
efficiency as v.x . (again assuming proper optimization).
 
F

Frank Birbacher

Hi!

Apart from what Victor says:

That gives the correct result, but not the best performance. A more
efficient solution would be

switch(i/2)
{
case 0: return v1[i%2]; break;
case 1: return v2[i%2]; break;
case 2: return z; break;
default: throw "bad index";
}

This is probably slower due to extra calculations
because v1[k] (as implemented in my earlier post) is much faster than

if ( k == 0 )
return v1.x;
else
return v1.y;

Are you aware of the fact that the "switch" statement is supposed to be
optimized by table lookup. That means it cannot be compare to a series
of if-else statements. The "switch" can have a performance of O(1).
Which is exactly the same as your array. And I guess the table-lookup
optimization for the "switch" statement is more likely implemented than
a combination of function inlining and constant array lookup.

This optimization is why a switch will only accept integral values.

Anyway, unless you have measured runtime performance of an array of
member pointers compared to a chained if-else compared to a switch,
there is no point in discussing which one could be faster. It just depends.

Frank
 
H

huili80

Hi!

Apart from what Victor says:

That gives the correct result, but not the best performance. A more
efficient solution would be
switch(i/2)
{
   case 0: return v1[i%2]; break;
   case 1: return v2[i%2]; break;
   case 2: return z; break;
   default: throw "bad index";
}

This is probably slower due to extra calculations
because  v1[k] (as implemented in my earlier post) is much faster than
if ( k == 0 )
   return v1.x;
else
   return v1.y;

Are you aware of the fact that the "switch" statement is supposed to be
optimized by table lookup. That means it cannot be compare to a series
of if-else statements. The "switch" can have a performance of O(1).
Which is exactly the same as your array. And I guess the table-lookup
optimization for the "switch" statement is more likely implemented than
a combination of function inlining and constant array lookup.

This optimization is why a switch will only accept integral values.

Anyway, unless you have measured runtime performance of an array of
member pointers compared to a chained if-else compared to a switch,
there is no point in discussing which one could be faster. It just depends.

Frank

I agree, without measurement it's meaningless to talk about
performance. But I wasn't asking about the performance in the first
place anyway (it appeared in a later example that was aksed for). Even
if the example was completely meansingless performance-wise, it
doesn't mean my question about "pointer to a member of a member" is
necessary meaningless.

I was trying to get an answer on how to get a "pointer to a member of
a member" if there exists something like that.
Maybe such a thing can be used in a good way, who knows.
 
A

Andrey Tarasevich

I was trying to get an answer on how to get a "pointer to a member of
a member" if there exists something like that.
Maybe such a thing can be used in a good way, who knows.

Of course, it can be. There's no real technical or conceptual difference
between 'pointer-to-data-member' and
'pointer-to-data-member-of-data-member'. They would be used in exactly
the same way.

Technically, the implementation of such a pointer would be exactly the
same as that of the existing 'pointer-to-data-member', meaning that the
pointer _type_ itself is already in the language. The only thing that's
really missing is the syntax that would let us to assign the proper
value to such a pointer.

Because of that latter part, the answer is no, you can't use such a
pointer in standard C++.
 
H

huili80

Of course, it can be. There's no real technical or conceptual difference
between 'pointer-to-data-member' and
'pointer-to-data-member-of-data-member'. They would be used in exactly
the same way.

Technically, the implementation of such a pointer would be exactly the
same as that of the existing 'pointer-to-data-member', meaning that the
pointer _type_ itself is already in the language. The only thing that's
really missing is the syntax that would let us to assign the proper
value to such a pointer.

Because of that latter part, the answer is no, you can't use such a
pointer in standard C++.

So since the pointer type is already in the language, but we just
can't assign a value to it, how can i explicitly get the type of the
pointer? (I just can't figure it out how...) Say what should we use to
replace the ... in the following so that ptr_type is a pointer to
B::a.x ?

class A { public: int x; };
class B { public: A a; };

typedef ... ptr_type;
 
G

Greg Herlihy

I mean, is it possible to achieve zero run-time overhead (assuming
proper optimization) in accessing members (and their members) via an
index?  If we don't have a vector5d::z (in which case it's actually a
4D vector), we might want to use an array of pointers to member of a
member (I don't know how even if they do exist). Having vector5d::z
makes this even more complicated in that a pointer to vector5d::z and
a (may or may not existing) pointer to vector5d::v1.x certainly would
have different types, so they cannot be put into an array.

If you really want to go ahead with a scheme to access class members
via an index, then I would suggest an implementation that takes the
opposite tack: that is, instead of accessing data members as if they
were elements of an array - access the elements of an array as if they
were individual data members.

Specifically, the vector classes could declare an array of doubles as
a member - and then declare various accessor methods that would return
the appropriate element from this array as the value of the
corresponding "virtual" data member. For example

class Vector2D
{
public:
Vector2D( x = 0.0, y = 0.0)
{
d_[0] = x;
d_[1] = y;
}

// operator[n] just returns d_[n]

double& operator[](int n)
{
assert(n >= and n <= sizeof(d_)/sizeof(d_[0]));

return d_[n];
}

// various methods for the "virtual" data members

double& x() { return d_[0]; }
const double& x() const { return d_[0]; }

double& x() { return d_[1]; }
const double& x() const { return d_[1]; }

private:
double d_[2];
};

class Vector3D
{
public:
Vector3D() : d_() {}

double& operator[](int n)
{
assert(n >= and n <= sizeof(d_)/sizeof(d_[0]));

return d_[n];
}

// Vector3D returns the v1 Vector2d "member" only on demand..

Vector2D v1() const { return Vector2D( d_[0], d_[1]); }

double v1_x() { return Vector2D( d_[0]; }
double v1_y() { return Vector2D( d_[1]); }

// declare v2 accessors here

double& z() { return d_[4]; }

private:
double[5] d_;
};

Greg
 
J

James Kanze

[...]
Are you aware of the fact that the "switch" statement is
supposed to be optimized by table lookup.

Not really. The switch statement (like everything else in the
basic languaage) is supposed to be optimized in the most
effective way possible on the given platform. For many
platforms, this does mean a table of pointers to code if the
switch is "dense". There are machines, however, on which an
indirect jump is exceedingly expensive, and the sequence of if's
is actually faster, even for dense tables. (Remember, the
compiler will know all of the values, and will generated a
binary search with the if's, so you have at most O(ln n)
comparisons.)

The real point is that the compiler knows the architecture for
which it is generating code, and will use whatever technique is
optimal for that architecture. Trying to second guess it can
never improve performance.

[...]
This optimization is why a switch will only accept integral values.

Integral *constant* values.
 
A

alexandrug

Say I have two classes:

class A
{
public:
int x;

};

class B
{
public:
A a;

};

Then how do I construct a member pointer to B::a.x ? What's the syntax
for it?
Thanks!

Here is my solution to your problem :

I declare a data member in the B class : the void pointer p,
and I initialize it with the help of the constructor of the B
class.

Hope you are happy with this solution.

-------------------------------------------------------------
class A
{
public:
int x;
};

class B
{
public:
A a;
void *p;
B()
{
B::p = &(B::a.x);
};
};

int main()
{

return 0;
}
 
H

huili80

Here is my solution to your problem :

I declare a data member in the B class : the void pointer p,
and I initialize it with the help of the constructor of the B
class.

Hope you are happy with this solution.

-------------------------------------------------------------
class A
    {
    public:
        int x;
    };

class B
    {
    public:
        A a;
        void *p;
        B()
        {
        B::p = &(B::a.x);
        };
    };

int main()
    {

    return 0;
    }

I'm very happy with the solution. Thank you!
But what if I don't want to increase the size of B?
 
A

alexandrug

Then the pointer would not be a member of the class B.

Not a member? How?

Let me illustrate a couple of things by an example. The purpose of
pointer-to-member types is to facilitate nameless selection of class
members (as opposed to named selection we usually use).

For example, consider this code sample

struct A { int a; }

struct B {
int x;
int y;
A a;
int z[10];
};

void zero(B* b, unsigned n, int B::*m) {
for (; n > 0; --n, ++b)
b->*m = 0;
}

Now, I can use the above simple 'zero' function I can set to zero any
immediate member of all 'B' objects in an array

B b[10];

zero(b, 10, &B::x); // sets all 'B::x's to zero
zero(b, 10, &B::y); // sets all 'B::y's to zero

Or I can choose what to zero based on some run-time criteria

zero(b, 10, rand() % 2 == 0 ? &B::x : &B::y);

This is the valuable run-time flexibility provided by pointers of
pointer-to-member type (in this case applied specifically to data members).

However, what if I want to zero 'B::a.x' members in the 'b' array? Or
what about zeroing 'B::z[5]' in each element of the 'b' array? In C++
you can't do that. And the truth is that from the implementation point
of view the above pointer type ('int B::*m') is already capable of
holding the required value (to point to either 'B::a.x' or 'B::z[5]'),
but the language simply has no syntax to assign that value to that
pointer. (It can be done with a hack though).

Your solution with a regular pointer inside 'B' will "work", but suffers
from a number of problems that essentially defeat the purpose in general
case. If it is good enough for the OPs specific case - great. But how
are you going to do it without placing anything into 'B'?

-------------------

Then how do I construct a member pointer to B::a.x ? What's the syntax
for it?

-------------------

From the initial post, I understood that a member pointer is a data
member of a class,
not a pointer to a member of a class or to anything else. So take my
postings as such.

Alex.
 
B

Bo Persson

Alf said:
* Victor Bazarov:

Not quite unanswered.

I forwarded an inquiry in comp.lang.c++.moderated about this to two
of the comp.std.c++ moderators, namely the two that last seemed to
be active, and the same day (I think it must be related...) Fergus
replied to that article, as follows:

<url:
http://groups.google.com/group/comp.lang.c++.moderated/msg/52a26fec00939fe5>:

* Fergus Henderson (comp.std.c++ moderator), on Jun 18 2008:


So, any takers?

It needs some stable company or organization such as a university
that can host the server, one that will most likely continue to
exist for many many years. I don't understand why they haven't
asked Google to do that. But then, I don't know much more than
anyone else about what happened, or didn't
happen.

We can only guess that there must be some very special requirements
for that account, as nobody else has been able to take over the
hosting for six months. Google is a good idea, or MS, or IBM, or
Intel, or HP, or Adobe, or Apple - just to mention a few of the
companies involved.

Can't be lack of hardware, can it? I have a spare PC, if it is...


Bo Persson
 
F

Frank Birbacher

Hi!

Andrey said:
For example, consider this code sample

struct A { int a; }

struct B {
int x;
int y;
A a;
int z[10];
};

void zero(B* b, unsigned n, int B::*m) {
for (; n > 0; --n, ++b)
b->*m = 0;
}

Now, I can use the above simple 'zero' function I can set to zero any
immediate member of all 'B' objects in an array

B b[10];

zero(b, 10, &B::x); // sets all 'B::x's to zero
zero(b, 10, &B::y); // sets all 'B::y's to zero

typedef int& (*BIntMember) (B*);

void zero(B*const b, unsigned const n, BIntMember const m) {
for(; n>0; --n, ++b)
m(b) = 0;
}

int& B_x(B*const b) { return b->x; }
int& B_y(B*const b) { return b->y; }
int& B_a_a(B*const b) { return b->a.a; }

B b[10];

zero(b, 10, &B_x);
zero(b, 10, &B_y);
zero(b, 10, &B_a_a);

OR using boost.lambda:

for_each(b, b+10, bind(&B_x, _1) = 0);
for_each(b, b+10, bind(&B_x, _1)++);
....

Frank
 

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
474,172
Messages
2,570,933
Members
47,473
Latest member
ChristelPe

Latest Threads

Top