pointer to member question

T

tkamin

The C++ standards (98, 03, 11) in section $5.3.1/3 defines that in
situation:
struct Base { int a; };
struct Derived : Base {};
The expression &Derived::a will return pointer of type int Base::*
instead of int Derived::*.

This solution causes some suprisings problems in code code that seem
to be perfectly valid.

1. Multiple indirect inheritance from one Base class, example;
struct Very_base { int a; };
struct Base1 : Very_base {};
struct Base2 : Very_base {};
struct Derived : Base1, Base2 {}

int main() {
Derived d;
d.Base1::a; //omit dis-ambiguity by explicit qualification as
defined in $10.1/5
d.Base2::a; //omit dis-ambiguity by explicit qualification as
defined in $10.1/5

&Derived::Base1::a; //Valid, yields int Very_base::*
&Derived::Base2::a; //Valid, yields int Very_base::*

int Derived:: * a_ptr = &Derived::Base1::a; //yields an error about
Very_base being ambiguous base class of Derived despite the
qualification
};

2. Problem with pointer to member pointer arguments. Lets assume that
we have:
struct Base { int a; };
struct Derived : Base { int b; };

//Member access generator to use with libraries that allows function
pointers only
template<typename Class, typename Member_type, Member_type Base:: *
ptr>
Member_type get(Class &c) { return c.*ptr; }

void call(int (*f)(Derived &));

int main()
{
call(&get<Derived, int, &Derived::b>); //Works correctly
call(&get<Derived, int, &Derived::a>); //Not working because
&Derived::a returns an int Base::* and no conversions are applied to
pointer to member (as specified in $14.3.2/5)
call(&get<Base, int, &Derived::a>); //Template function is
instantiated properly but has incompatible
}

3. Private inheritance:
struct Base { int a; };
struct Derived : private Base
{
public:
using Base::a; //make a accessible
};

int main()
{
Derived d;
d.a; //valid
&Derived::a; //Valid, Derived::a is accessible at this poin
int Derived::* ptr = &Derived::a; //Conversion from int Base::* to
int Derived::* is illegal because the base class is inaccessible as
defined in $4.11/2
}

None of this problems will occure if the expression &class::member
would always return decltype(class::member) class::* pointer.

Was there any reason for specifing this expression to return pointer
to base class in some situation?
 
G

Gil

The C++ standards (98, 03, 11) in section $5.3.1/3 defines that in
situation:
struct Base { int a; };
struct Derived : Base {};
The expression &Derived::a will return pointer of type int Base::*
instead of int Derived::*.

None of this problems will occure if the expression &class::member
would always return decltype(class::member) class::* pointer.

Was there any reason for specifing this expression to return pointer
to base class in some situation?

they had to make a call and they wanted to allow the more generic
approach since a pointer to base member can be implicitly converted
to a pointer to derived member.

your proposal would have constrained the type being initialized to
the nested name specifier only and not to the whole hierarchy.

I tend to agree with committee's call on this issue: considering
your examples, 1 is somehow ok because the conversion makes it
ambiguous, not the result of unary& operator per se; 3 is a corner
case where accessibility is checked at conversion (but why use
conversion); case 2 is a little more embarassing because of the
non type template parameter conversion limitation but once one
agrees to use pointer to base types the situation goes away.

there's another example that pops up on forums and unfortunately
it is quite realistic

template< typename Ret, typename C >
Ret get( Ret (C::*member) )
{
return C().*member; /*imagine C has abstract base deep in hier*/
}

but again, imo the fact that the library author can manipulate
yet to be defined pointer to derived types through its base types
overcomes all these minuses.

hth,
gil
 
T

tkamin

they had to make a call and they wanted to allow the more generic
approach since a pointer to base member can be implicitly converted
to a pointer to derived member.
Wich allows some bad looking code as Base().(&Derived::a) or
int Base::*ptr = &Derived::a will looks as implicit pointer to Derived
to pointer to Base cast which are not allowed in standard.
your proposal would have constrained the type being initialized to
the nested name specifier only and not to the whole hierarchy.
But in situation when pointer to base is neded, then it may be use
explicity
by &Basse::a.
I tend to agree with committee's call on this issue: considering
your examples, 1 is somehow ok because the conversion makes it
ambiguous, not the result of unary& operator per se; 3 is a corner
case where accessibility is checked at conversion (but why use
conversion); case 2 is a little more embarassing because of the
non type template parameter conversion limitation but once one
agrees to use pointer to base types the situation goes away.

there's another example that pops up on forums and unfortunately
it is quite realistic

template< typename Ret, typename C >
Ret get( Ret (C::*member) )
{
  return C().*member; /*imagine C has abstract base deep in hier*/
}

but again, imo the fact that the library author can manipulate
yet to be defined pointer to derived types through its base types
overcomes all these minuses.
Could you expand this? Bacause I don't understand fully what you mean.
 

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,039
Messages
2,570,375
Members
47,020
Latest member
anuradha

Latest Threads

Top