f



lookup of class members qualified by a derived class name

Hi,

can anyone point me to the exact paragraph in the standard which
makes the following ill-formed?

struct Base { int i; };
struct Derived : Base { };

int main(){
    Base b = { 0 };
    return b.Derived::i; // ill-formed
}

Note that "i" looked up in the scope of "Derived" is actually "Base::i"
and for example the expression "b.* &Derived::i" is well-formed.

Regards,
Vladimir Marko


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
swelef (4)
10/20/2006 2:28:43 PM
comp.lang.c++.moderated 10738 articles. 1 followers. allnor (8510) is leader. Post Follow

8 Replies
360 Views

Similar Articles

[PageSpeed] 14

Vladimir Marko ha scritto:

> Hi,
>
> can anyone point me to the exact paragraph in the standard which
> makes the following ill-formed?
3.4.5/4

HTH
Gianluca


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Gianluca
10/20/2006 5:16:39 PM
Gianluca Silvestri wrote:
> Vladimir Marko ha scritto:
>
> > Hi,
> >
> > can anyone point me to the exact paragraph in the standard which
> > makes the following ill-formed?
> 3.4.5/4
>
> HTH
> Gianluca

3.4.5/4 If the id-expression in a class member access is a qualified-id
     of the form

         class-name-or-namespace-name::...

     the class-name-or-namespace-name following the . or -> operator
     is looked up both in the context of the entire postfix-expression
     and in the scope of the class of the object expression. If the name
     is found only in the scope of the class of the object expression,
     the name shall refer to a class-name. If the name is found only in
     the context of the entire postfix-expression, the name shall refer
     to a class-name or namespace-name. If the name is found in both
     contexts, the class-name-or-namespace-name shall refer to the
     same entity. [Note: the result of looking up the
     class-name-or-namespace-name is not required to be a unique
     base class of the class type of the object expression, as long as
     the entity or entities named by the qualified-id are members of
     the class type of the object expression and are not ambiguous
     according to class.member.lookup. ...]

That's funny. I've got the feeling that the standard must differ from
the final draft (which I quoted above), otherwise it should actually be
well-formed. The "Derived" is surely found (only) in the context of
the entire postfix-expression, isn't it? And the Note only supports
it since "Derived::i" names the entity "Base::i" which is a member
of "Base" and is not ambiguous.

Regards,
Vladimir Marko


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Vladimir
10/21/2006 1:15:36 AM
Vladimir Marko wrote:
> Hi,
>
> can anyone point me to the exact paragraph in the standard which
> makes the following ill-formed?
>
> struct Base { int i; };
> struct Derived : Base { };
>
> int main(){
>     Base b = { 0 };
>     return b.Derived::i; // ill-formed
> }

�5.2.5 describes class member access. When using a dot "." or arrow
"->" the expression to the right "shall name a member of the class or
of one of its base classes." Since there is no "Derived" object
anywhere to be found in an object of type Base, the expression is
ill-formed.

> Note that "i" looked up in the scope of "Derived" is actually "Base::i"
> and for example the expression "b.* &Derived::i" is well-formed.

No, the expression:

      b.* &Derived::i;

is completely different - it does not involve any class scope name
lookup at all. For one, this expression uses a different operator,
".*". And unlike operators "." and "->"  the ".*"operator is binary,
meaning that the expression is evaluated by applying the right-hand
operand, a pointer-to-member value, &Derived::i, to the left-hand
operand of a matching class type.

Since the Derived class member i is declared a member of its Base
subobject, the type of the righthand pointer-to-member expression is
actually:

      int Base::*

which, as luck would have it, is a pointer to member of exactly the
same class as the class of the lefthand operand - so the expression is
both well-formed and has a defined value.

Greg


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Greg
10/21/2006 5:48:02 AM
Greg Herlihy wrote:
> Vladimir Marko wrote:
> > Hi,
> >
> > can anyone point me to the exact paragraph in the standard which
> > makes the following ill-formed?
> >
> > struct Base { int i; };
> > struct Derived : Base { };
> >
> > int main(){
> >     Base b = { 0 };
> >     return b.Derived::i; // ill-formed
> > }
>
> �5.2.5 describes class member access. When using a dot "." or arrow
> "->" the expression to the right "shall name a member of the class or
> of one of its base classes." Since there is no "Derived" object
> anywhere to be found in an object of type Base, the expression is
> ill-formed.

There's a little problem with the interpretation of the verb "name"
here. Does Derived::i "name" the entity Base::i? If it does,
b.Derived::i should be well-formed. If it doesn't, the expression
d.Derived::i where d is an object of class Derived should be
ill-formed. Both options are wrong. Am I missing something?

> > Note that "i" looked up in the scope of "Derived" is actually "Base::i"
> > and for example the expression "b.* &Derived::i" is well-formed.
>
> No, the expression:
>       b.* &Derived::i;
> is completely different [...]

I know that, I just wanted to point out the inconsistency.

Regards,
Vladimir Marko


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Vladimir
10/22/2006 3:37:04 AM
Vladimir Marko wrote:
> > > struct Base { int i; };
> > > struct Derived : Base { };
> > >
> > > int main(){
> > >     Base b = { 0 };
> > >     return b.Derived::i; // ill-formed
> > > }
> >
> There's a little problem with the interpretation of the verb "name"
> here. Does Derived::i "name" the entity Base::i?

No, it does not. It names the entitiy "Derived::i".

> If it does,
> b.Derived::i should be well-formed. If it doesn't, the expression
> d.Derived::i where d is an object of class Derived should be
> ill-formed.

Why? Since the Derived class does have a member i, references to
Derived::i are perfectly valid. How could they not be?

> > > Note that "i" looked up in the scope of "Derived" is actually "Base::i"
> > > and for example the expression "b.* &Derived::i" is well-formed.
> >
> > No, the expression:
> >       b.* &Derived::i;
> > is completely different [...]
>
> I know that, I just wanted to point out the inconsistency.

Thre is no inconsistency. You are confusing the name of a member
variable from the type of a member pointer variable. The names
Derived::i and Base::i are not equivalent (so the latter cannot
substitute for the former), but the types of the the two member
pointers, &Derived::i and &Base::i do happen to be the same (so the
latter may substitute for the former).

Greg


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Greg
10/22/2006 8:25:34 AM
Greg Herlihy wrote:
> Vladimir Marko wrote:
> > > > struct Base { int i; };
> > > > struct Derived : Base { };
> > > >
> > > > int main(){
> > > >     Base b = { 0 };
> > > >     return b.Derived::i; // ill-formed
> > > > }
> > >
> > > �5.2.5 describes class member access. When using a dot "." or arrow
> > > "->" the expression to the right "shall name a member of the class or
> > > of one of its base classes." Since there is no "Derived" object
> > > anywhere to be found in an object of type Base, the expression is
> > > ill-formed.
> >
> > There's a little problem with the interpretation of the verb "name"
> > here. Does Derived::i "name" the entity Base::i?
>
> No, it does not. It names the entitiy "Derived::i".

You seem not to understand the distiction I make between an
id-expression and the _entity_ it maps to. The whole name lookup is
about mapping id-expressions to _entities_.

There is no _entity_ Derived::i, there is only the _entity_ Base::i of
Derived's base class subobject. Consider this:

A new member i of Derived can hide the name of the _entity_ Base::i but
it can't hide the name of any previously declared _entities_ Derived::i
if any (it will either overload them or conflict with them)].

> > If it does,
> > b.Derived::i should be well-formed. If it doesn't, the expression
> > d.Derived::i where d is an object of class Derived should be
> > ill-formed.
>
> Why? Since the Derived class does have a member i, references to
> Derived::i are perfectly valid. How could they not be?

No, Derived does _not_ have a member i, it's base class subobject
has a member i which is visible in the scope of Derived.

> > > > Note that "i" looked up in the scope of "Derived" is actually "Base::i"
> > > > and for example the expression "b.* &Derived::i" is well-formed.
> > >
> > > No, the expression:
> > >       b.* &Derived::i;
> > > is completely different [...]
> >
> > I know that, I just wanted to point out the inconsistency.
>
> Thre is no inconsistency. You are confusing the name of a member
> variable from the type of a member pointer variable. The names
> Derived::i and Base::i are not equivalent (so the latter cannot
> substitute for the former), but the types of the the two member
> pointers, &Derived::i and &Base::i do happen to be the same (so the
> latter may substitute for the former).

I'm not confusing anything. I'm pointing out the non-intuitive
differences in mapping the qualified-id Derived::i to some _entity_
in different contexts.

Regards,
Vladimir


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Vladimir
10/22/2006 2:30:01 PM
Vladimir Marko wrote:
> Greg Herlihy wrote:
> > Vladimir Marko wrote:
> > > > > struct Base { int i; };
> > > > > struct Derived : Base { };
> > > > >
> > > > > int main(){
> > > > >     Base b = { 0 };
> > > > >     return b.Derived::i; // ill-formed
> > > > > }
> > > > > Note that "i" looked up in the scope of "Derived" is actually "Base::i"
> > > > > and for example the expression "b.* &Derived::i" is well-formed.
> > > >
> > > > No, the expression:
> > > >       b.* &Derived::i;
> > > > is completely different [...]

The first example tries to find Derived::i within the class scope of
Base (which, intuitively, should fail - since there is no Derived
object to be found in Base).

In the second example, &Derived::i is looked up in the global
namespace; so, intuitively, one would expect &Derived::i to be found
because the Derived class is in fact declared within the global
namespace.

Greg


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Greg
10/23/2006 7:09:02 AM
Greg Herlihy wrote:
> Vladimir Marko wrote:
> > Greg Herlihy wrote:
> > > Vladimir Marko wrote:
> > > > > > struct Base { int i; };
> > > > > > struct Derived : Base { };
> > > > > >
> > > > > > int main(){
> > > > > >     Base b = { 0 };
> > > > > >     return b.Derived::i; // ill-formed
> > > > > > }
>
> The first example tries to find Derived::i within the class scope of
> Base (which, intuitively, should fail - since there is no Derived
> object to be found in Base).

And i'm looking for the paragraph that says so. Gianluca Silvestri
suggested 3.4.5/4 but that's not it. It says only that Derived is
looked up both in the context of the entire postfix-expression (to find
typedefs for Base) and in the context of the class of the object
expression. There is, however, the non-normative note:
     [Note: the result of looking up the class-name-or-namespace-name is
     not required to be a unique base class of the class type of the
     object expression, as long as the entity or entities named by the
     qualified-id are members of the class type of the object expression
     and are not ambiguous according to class.member.lookup. [...]]
which IIRC suggests that i should be looked up in the scope of Derived
and only the found entity needs to be an unambiguous member of the
object expression.

> > No, Derived does _not_ have a member i, it's base class subobject
> > has a member i which is visible in the scope of Derived.

I must correct that statement. According to

10/1 [...] Unless redefined in the derived class, members of a base
     class are also considered to be members of the derived class. [...]

i is actually a member of Derived. So, I'll just maintain that in the
expression d.Derived::i the qualified-id Derived::i names the entity
Base::i which is a member of Derived.

Regards,
Vladimir Marko


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Vladimir
10/23/2006 12:01:31 PM
Reply: