Topic: does qualifying a method name select a receiver subobject?


Author: "Scott McPeak" <smcpeak@cs.berkeley.edu>
Date: Sun, 19 Feb 2006 19:23:05 CST
Raw View
I've found the answer, in 10.1/4:

  In such lattices, explicit qualification can be used to specify which
subobject is meant.

This text is inside "example" brackets, so is technically not
normative,
but I think that's just a typographic oversight.

Also, FWIW, the example code can be simplified to just make 'foo' a
nonstatic data member, and 'bar' attempt to return B::foo.

---
[ 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                       ]





Author: "Scott McPeak" <smcpeak@cs.berkeley.edu>
Date: Wed, 15 Feb 2006 12:53:36 CST
Raw View
Consider this code:

  struct A {
    void foo();
  };

  struct B : A {
  };

  struct C : A, B {            //    A A
    void bar();                //    | |
  };                           //    | B
                               //    |/
  void C::bar()                //    C
  {
    (*this).B::foo();
  }

My question is whether the call to foo is ambiguous.

Clearly, had the call been "A::foo()", it would be ambiguous because
there are two subobjects of type A [10.2/2].

Also clearly, the *intent* of the code is to invoke foo while passing
the A subobject contained in the B subobject, rather than the one
directly contained in the C subobject.  That is, providing a qualifier
for the name foo is intended to also select a receiver subobject.

However, I cannot find any justification for allowing this code (and
its obvious intended semantics) in the standard.

-- My analysis of the standard's interpretation of the call to foo. --

1. The expression "(*this)" is an lvalue of type "C" [9.3.2/1,
5.3.1/1].

2. The name "B" looks up to the class B [3.4.5/4].

3. The name "foo" is looked up in class B [3.4.3.1/1], which
unambiguously finds "A::foo" [10.2/2], which is not overloaded.


4. The "this" parameter of the callee is initialized as if by direct
an explicit type conversion of the pointer to the object of the call
[5.2.2/4], where "object of the call" means the object denoted by
"(*this)".  Thus, the source pointer has type "C*".

5. The type of the "this" parameter of A::foo is A* [9.3.2/1].

6. The explicit type conversion from "C*" to "A*" would be equivalent
to a static_cast [5.4/5], which in turn is equivalent to a cast-free
initialization [5.2.9/2], which in turn would use standard conversions
[8.5/14, last bullet], of which the pointer conversion from derived to
base class is the relevant one, but requires that the conversion be
unambiguous [4.10/3], but it is not [10.2/7].

Hence the call is ill-formed.

-- Further discussion --

The crucial steps above are of course 3 and 5, which conclude that the
"this" parameter of the callee has type A*.  The code's intent is that
is has type B* because it was found by looking in B.  But I can find
nothing that would connect the lookup procedure for foo to its type
once found.

Moreover, it is *not* the case that inheritance "copies" all the base
class members into the derived class [13.2/1], so we can't just
pretend that there is a copy of A::foo called B::foo in B.

However, 10/1 says in part:

  Unless redefined in the derived class, members of a base class are
  also considered to be members of the derived class.

What does this actually mean?  When, exactly, are they "considered"
members of the derived class?  10.2/2 is pretty clear about treating
base class members differently from derived class members.

Furthermore, 9.3.2/4 gives rules for matching the cv-qualification of
the object of the call and the "this" parameter; yet the analysis
above suggests this is redundant, since 9.3.2/1 specifies how "this"
acquires the cv-qualifiers of the method, and (as above) the rules for
standard convertibility imply everything in 9.3.2/4.  So either
9.3.2/4 is redundant, or something is wrong with my analysis.

-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.jamesd.demon.co.uk/csc/faq.html                       ]