C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Why is pointer-to-member-of-member not possible?

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards
View previous topic :: View next topic  
Author Message
Steve Rencontre
Guest





PostPosted: Fri Feb 17, 2006 6:59 am    Post subject: Why is pointer-to-member-of-member not possible? Reply with quote



Following discussions in c.l.c++ and elsewhere, it's pretty clear that
the following is not possible in C++, but it was suggested I ask here
for the rationale why.

Basically, I have:

struct S1 { int a1; };
struct S2 ( S1 s1; int a2; };

What I want is a pointer-to-member which will let me access either of
the ints in S2 - that is, I'd like to be able to say,

S2 s2;
int S2::*p;

p = &S2::a2; // fine
s2.*p = 123; // equivalent to s2.a2 = 123

p = &S2::s1.a1; // ILLEGAL!
s2.*p = 345; // would be equiv to s2.s1.a1 = 345

Now sure, I understand why '&S2::s1.a1' is illegal in terms of the C++
syntax rules, but it seems to me that it's both meaningful and
reasonable (if not common!) to want to do it.

I can, of course, get the effect I want in true C hacker style with,

size_t offset = offsetof (S2, s1.a1);
*(int *) ((char *) &s2 + offset) = 345;

which, while ugly, is legal and portable.

Can anyone enlighten me as to /why/ there is no syntax for this which is
a bit closer to the spirit of C++?

Thanks.

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Back to top
Greg Herlihy
Guest





PostPosted: Sun Feb 19, 2006 4:18 pm    Post subject: Re: Why is pointer-to-member-of-member not possible? Reply with quote



Steve Rencontre wrote:
Quote:
Following discussions in c.l.c++ and elsewhere, it's pretty clear that
the following is not possible in C++, but it was suggested I ask here
for the rationale why.

Basically, I have:

struct S1 { int a1; };
struct S2 ( S1 s1; int a2; };

What I want is a pointer-to-member which will let me access either of
the ints in S2 - that is, I'd like to be able to say,

S2 s2;
int S2::*p;

p = &S2::a2; // fine
s2.*p = 123; // equivalent to s2.a2 = 123

p = &S2::s1.a1; // ILLEGAL!
s2.*p = 345; // would be equiv to s2.s1.a1 = 345

Now sure, I understand why '&S2::s1.a1' is illegal in terms of the C++
syntax rules, but it seems to me that it's both meaningful and
reasonable (if not common!) to want to do it.

I can, of course, get the effect I want in true C hacker style with,

size_t offset = offsetof (S2, s1.a1);
*(int *) ((char *) &s2 + offset) = 345;

which, while ugly, is legal and portable.

Can anyone enlighten me as to /why/ there is no syntax for this which is
a bit closer to the spirit of C++?

C++ could support a "member member pointer" but for the language to do
so, the Standard would have treat it as its own pointer type - one
distinct from the member pointer type that it currently supports. The
reason for having to do so would be the additional storage requirements
necessitated by the additional level of reference in the pointer.

Recall that a member pointer, such as int S2::*, must be capable of
pointing to any int member of S2 (whether S2 has only one int member or
100 such members). The requirements of the member pointer's
representation are independent of the class's actual definition. So
even if S2 has no int members, an int S2::* member pointer is
unchanged: and has the same storage requirements for an S2 class
defined with any number of members of type int. So it would be
reasonable to expect that a member member pointer would require twice
the storage of a member pointer, and therefore could be treated as the
same type.

Language support for a member member pointer would naturally prompt the
question, well why not also support a member member member pointer?
Since each additional level of membership effectively requires a new
pointer type, the Standard would have to specify how many of these new
pointer types (that is, how many layers of membership should be
navigable via a pointer) a conforming implementation would have to
support (I think 6 sounds about right. Anyone else?).

When considering any possible addition to the language, the preference
is always to find a comparable alternative using the current facilities
of the language. One reason is to prevent "feature sprawl" since a
language that incorporated every suggestion would be so large as to
become unmanageable (well, it could also turn into Perl Smile. But
another reason is that a custom implementation can usually be fine
tuned to achieve the desired behavior; while a feature incorporated
into the language may not provide such flexibility. And indeed, the
recursive nature of a member member pointer suggests at least one
existing C++ technique - namely templates - that when combined with
operator overloading could perhaps provide a member member pointer
implementation.

What would a member member pointer implementation look like? Well, I
can show what I came up with. And while my implementation will probably
not be appearing in <functional> anytime soon, I think this code does
show that the C++ as a language is user-extensible - and often to a
surprising (at least for me) degree:

#include <cstddef>
#include <iostream>

template<class T, class M1, class M2>
class member_member_ptr
{
public:
typedef M1 T::*outer;
typedef M2 M1::*inner;

member_member_ptr(outer mp1, inner mp2) :
m_outer(mp1),
m_inner(mp2)
{
}

M2 operator->*(const T& c)
{
return &(&c->*m_outer)->*m_inner;
}

private:
outer m_outer;
inner m_inner;
};

// Test case

struct S2
{
S2() : b(42)
{
}
int b;
};

struct S1
{
S2 s2;
int a;
};

// helper template creation function

template <class C, class M1, class M2>
member_member_ptr<C,M1,M2>
inline mm_ptr( M1 C::*mp1, M2 M1::*mp2)
{
return member_member_ptr<C,M1,M2>(mp1,mp2);
}

int main()
{
// declare an instance of S1
S1 s;

// apply member member pointer
// to retrieve s.s2.b
int b = mm_ptr(&S1::s2, &S2::b)->*s;

// inspect result
std::cout << "b is " << b << "\n";
}

Output:
b is 42

Greg

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Back to top
Steve Rencontre
Guest





PostPosted: Sun Feb 19, 2006 11:46 pm    Post subject: Re: Why is pointer-to-member-of-member not possible? Reply with quote



Thanks for your more detailed reply here, but my response is the same as
the one to your post in c.l.c++, to wit:

Greg wrote:

Quote:
I would suggest focussing on the capabilities of the pointer you are
asking for - and not on the relatively simple manner with which you
intend to use it.

In an ultimate sense, yes, but my requirement is strictly in the context
of a POD struct, and I can't conceive of any situation in which what I
want doesn't boil down to a simple numerical offset. This may be a
failure of my imagination, but I don't think so.

TBH, I can't think of /any/ situation in which the address of a data
item relative to the base address of its containing object is not a
compile-time constant, and I'd be fascinated if you could give me an
example.

Sure, there are (non-ISO) concepts like MSVC++ properties, which /look/
like simple data items but aren't, but I'm not asking for that. A
pointer-to-data-member that actually referenced a property in that sense
would be a weird and wonderful thing. Sticking within the normal
definition of data members, though, I really don't see where the problem
lies.

To expand a little further, can you give me an instance of a case in
which the offsetof() hack would /not/ work? I can, of course, wrap
/that/ in a macro or template, but that's just wallpapering over the
ugliness, and I'd prefer something more intrinsically beautiful.

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Back to top
skaller
Guest





PostPosted: Fri Mar 03, 2006 8:06 am    Post subject: Re: Why is pointer-to-member-of-member not possible? Reply with quote

On Fri, 17 Feb 2006 00:59:30 -0600, Steve Rencontre wrote:

Quote:
Following discussions in c.l.c++ and elsewhere, it's pretty clear that
the following is not possible in C++, but it was suggested I ask here
for the rationale why.

Basically, I have:

struct S1 { int a1; };
struct S2 ( S1 s1; int a2; };


Can anyone enlighten me as to /why/ there is no syntax for this which is
a bit closer to the spirit of C++?

Politics. The committee didn't consider a complete algebraic
type model for pointers to members to be a high priority.
Therefore they ignored my proposal in this respect.

For this reason, you should just use C offsetof() macro,
and ptrdiff_t, since it is complete if not type safe,
and complain about the rule that prohibits
taking the offset of a member of a constructible type.

The correct way to handle this is very simple and quite
obvious. However you have missed the most
important part of the proposal which is more
general than your example suggests:

S2 S1::*p1; // offset of an S2 in S1
int S2::*p2; // offset of an int in S2
int S1::*p3; // offset of an int in S1

p1 = &S2::s1; // fine
p2 = &S1::a1; // fine
p3 = &S1::s1.a1; // ERROR!

You complained about the lack illustrated on this line
and so missed the real point:

p3 = p1 . p2; // ADD offsets

Adding offsetof()/ptrdiff_t offsets in C is no problem!
The fact C++ doesn't provide the correct typesafe operator
to do this is inexcusable. It isn't as if the idea and a
sketch of a proposal was not presented.

Note that it isn't immediately obvious .. but operator . is
the CORRECT notation to use for addition of offsets (you'll
realise this after thinking about it for a while).

Offset addition is associative. In particular delayed binding
to pointers should be possible: this works now:

int *pi;
S2 *ps2;
pi = (ps2 .* p1) .* p2;

but you cannot apply the associative law:

pi = ps .* (p1 . p2);
= ps .* p3;

This is just daft.

You can fix the problem easily using:

template <class Container, class Member>
class ptm {
ptrdiff_t offset;
public:
ptm(ptrdiff_t o) : offset(o) {}
..
};

and then overload operator +. However you will have
to use offsetof() to obtain the offset and pass it to
the constructor. Such offsets are NOT compatible with
C++ pointers to members, which are best not used at all,
since they don't provide a complete algebra. Offsetof
with a few templates can.

The main problem with the template solution is that
C++ notion of const is broken and can't be generalised.
So whilst providing templates for pointers to members
is easy for non-const cases, it will never work if you
want to take constness into account. A native implementation
would handle that.


--
John Skaller <skaller at users dot sourceforge dot net>
Async P/L, Realtime software consultants
Felix for C/C++ programmers http://felix.sourceforge.net


---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Martin Bonner
Guest





PostPosted: Wed Mar 08, 2006 4:07 pm    Post subject: Re: Why is pointer-to-member-of-member not possible? Reply with quote

Steve Rencontre wrote:
Quote:
Thanks for your more detailed reply here, but my response is the same as
the one to your post in c.l.c++, to wit:

Greg wrote:

I would suggest focussing on the capabilities of the pointer you are
asking for - and not on the relatively simple manner with which you
intend to use it.

In an ultimate sense, yes, but my requirement is strictly in the context
of a POD struct, and I can't conceive of any situation in which what I
want doesn't boil down to a simple numerical offset. This may be a
failure of my imagination, but I don't think so.

TBH, I can't think of /any/ situation in which the address of a data
item relative to the base address of its containing object is not a
compile-time constant, and I'd be fascinated if you could give me an
example.

In the context of POD objects, no. But consider:

.. struct vb { int vbi };
.. struct s : virtual vb { int si };

The offset of vbi from the start of s is not a compile time constant,
but has to be evaluated at run-time.
Quote:

Sure, there are (non-ISO) concepts like MSVC++ properties, which /look/
like simple data items but aren't, but I'm not asking for that. A
pointer-to-data-member that actually referenced a property in that sense
would be a weird and wonderful thing. Sticking within the normal
definition of data members, though, I really don't see where the problem
lies.

I don't actually see that they would be much worse. They would have to
be pointers to get and set functions under the hood, but nothing that
isn't readily implemented.
Quote:

To expand a little further, can you give me an instance of a case in
which the offsetof() hack would /not/ work? I can, of course, wrap
/that/ in a macro or template, but that's just wallpapering over the
ugliness, and I'd prefer something more intrinsically beautiful.

See above.

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Steve Rencontre
Guest





PostPosted: Wed Mar 08, 2006 8:06 pm    Post subject: Re: Why is pointer-to-member-of-member not possible? Reply with quote

Martin Bonner wrote:
Quote:
Steve Rencontre wrote:

TBH, I can't think of /any/ situation in which the address of a data
item relative to the base address of its containing object is not a
compile-time constant, and I'd be fascinated if you could give me an
example.

In the context of POD objects, no. But consider:

. struct vb { int vbi };
. struct s : virtual vb { int si };


Fair enough! I guess I still had POD too firmly in my head.

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
n2xssvv g02gfr12930
Guest





PostPosted: Fri Mar 10, 2006 8:06 pm    Post subject: Re: Why is pointer-to-member-of-member not possible? Reply with quote

Steve Rencontre wrote:
Quote:
Following discussions in c.l.c++ and elsewhere, it's pretty clear that
the following is not possible in C++, but it was suggested I ask here
for the rationale why.

Basically, I have:

struct S1 { int a1; };
struct S2 ( S1 s1; int a2; };

What I want is a pointer-to-member which will let me access either of
the ints in S2 - that is, I'd like to be able to say,

S2 s2;
int S2::*p;

p = &S2::a2; // fine
s2.*p = 123; // equivalent to s2.a2 = 123

p = &S2::s1.a1; // ILLEGAL!
s2.*p = 345; // would be equiv to s2.s1.a1 = 345

Now sure, I understand why '&S2::s1.a1' is illegal in terms of the C++
syntax rules, but it seems to me that it's both meaningful and
reasonable (if not common!) to want to do it.

I can, of course, get the effect I want in true C hacker style with,

size_t offset = offsetof (S2, s1.a1);
*(int *) ((char *) &s2 + offset) = 345;

which, while ugly, is legal and portable.

Can anyone enlighten me as to /why/ there is no syntax for this which is
a bit closer to the spirit of C++?

Thanks.

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]


p is a pointer to an int member of an S2 object
not a pointer to an int member of an S1 object
the only way to have p able to point to either
is to have a union of the 2 pointer types.

{
struct S1
{
int a1;
};
struct S2
{
S1 a1;
int a2;
};
union
{
int S1::*s1;
int S2::*s2;
}
p;
S2 s2;
p.s2 = &S2::a2;
s2.*p.s2 = 5;
p.s1 = &S1::a1;
s2.a1.*p.s1 = 7;
}

Personally I don't recommend this sort of thing as any misuse will
potentially cause serious bugs that will be very difficult to fix.

If you want a pointer to member of a member why not create a template
class. Below is a start at defining such a beast.

template <typename BASE,typename M1, typename M2>
class MyM2Pointer
{
private:
M1 BASE::*p1;
M2 M1::*p2;
public:
};

JB

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Steve Rencontre
Guest





PostPosted: Mon Mar 13, 2006 4:06 pm    Post subject: Re: Why is pointer-to-member-of-member not possible? Reply with quote

n2xssvv g02gfr12930 wrote:

Quote:
p is a pointer to an int member of an S2 object
not a pointer to an int member of an S1 object
the only way to have p able to point to either
is to have a union of the 2 pointer types.

Thanks for the response, but you miss my point. I was originally after a
syntactical construct which was identical in both cases, but this isn't
possible in C++. The union just complicates things without changing that
fact.

All I was really asking here was /why/ I couldn't do something in a nice
C++-like fashion instead of having to bodge it with offsetof and casts.

I think the answer resolves to something like:

Nobody suggested doing it, or if they did, nobody on the
Committee thought it worth the effort, given that there are
cases in which it /couldn't/ work. If you want it that badly, hey,
you've got offsetof!

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Scott Meyers
Guest





PostPosted: Sun Mar 19, 2006 9:06 pm    Post subject: Re: Why is pointer-to-member-of-member not possible? Reply with quote

Martin Bonner wrote:
Quote:
In the context of POD objects, no. But consider:

. struct vb { int vbi };
. struct s : virtual vb { int si };

The offset of vbi from the start of s is not a compile time constant,
but has to be evaluated at run-time.

As long as you know the complete hierarchy, computing the offset of each data
member of an object is easy. The problem arising from virtual inheritance is
that, given a pointer or reference to a base only, the distance from the base
subobject to data members of the most derived class depends on the hierarchy,
and you don't know that until you've seen the most derived class.

My understanding is that the way such cases are handled is that the most derived
constructor does whatever is necessary to make it possible to find derived class
fields given a base class pointer or reference (e.g., initialize
vbase-to-derived pointers or put values in offset tables stored off the vtbl),
but the distance from the virtual base to the derived fields is known *during
compilation* at the time the code for the most derived constructor is generated.

In the code above, the offset from vbi to the start of s is constant and
computable during compilation, but only if you know that no further classes
derive from s -- if you know the complete hierarchy. Which, in general, you
can't know.

Scott

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.