I do not think that any of them are poorly formed. First, for using X::f2 , X scanned, and this will uniquely give the type of class X Then f2 in X scanned, and this is also unambiguous (it is not scanned in D !).
The second case will work for the same reason.
But if you call f2 on object D , the call will be ambiguous, because the name f2 looked up in all subobjects D type X , and D has two such subobjects, and f2 is a non-static member function. The same reason holds for the second case. It doesn't matter if you call f3 directly with Z::X or X Both of them stand for class X
To get ambiguity for a using declaration, you need to write it in different ways. Note that in C ++ 0x using ThisClass::...; not valid. This is in C ++ 03, though, if the whole name refers to a member of the base class.
Conversely, if it is allowed in C ++ 0x, all use of the declaration will also be valid, because C ++ 0x does not take into account subobjects to search for a name: D::f2 uniquely refers to only one declaration (the one in X ). See DR # 39 and final article N1626 .
struct D : Y, Z{ // ambiguous: f2 is declared in X, and X is a an ambiguous base class using D::f2; // still fine (if not referred to by calls/etc) :) using Z::X::f3; }; struct E : D { // ambiguous in C++03 // fine in C++0x (if not referred to by an object-context (such as a call)). using D::f2; };
The C ++ 03 standard describes this in paragraphs 10.2 and 3.4.3.1 .
Answer for Edit3 :
Yes, GCC and VS2010 are wrong. trouble refers to the type found in the name of the introduced class ::trouble , and to the nested class found as Y::trouble . The trouble name preceding :: is looked up using an unqualified search (through 3.4.1/7 , which delegates 10.2 in the first pool), ignoring any names of objects, functions and enumerators ( 3.4.3/1 - there are no such names in this case, although). He then violates requirement 10.2 :
If the result set of ads is not all of the sub-objects of the same type ... the program is poorly formed.
It is possible that VS2010 and GCC interpret the C ++ 0x wording differently from Comeau, and retroactively implement this wording:
In a usage declaration used as a member declaration, the sub-name specifier must name the base class of the class being defined.
This means that not base classes are considered, but this is an error if a non-base class is named. If the Standard intends to ignore the names of a non-base class, it would say that it can only be here, or specify it explicitly (both practices are fulfilled). The standard, however, is in no way associated with its use and can. And GCC implements the C ++ 0x wording because it rejects otherwise completely fine C ++ 03 code, because the usage declaration contains its class name.
As an example of a fuzzy formulation, consider the following expression:
a.~A();
This is syntactically ambiguous because it can be a call to a member function if a is an object of a class, but it can be a pseudo-destructor call (which is a non-operator) if a has a scalar of type (e.g. int ). But what the Standard says for the pseudo-destructor invocation syntax and access to the class member in 5.2.4 and 5.2.5 respectively
The left side of the point operator must be scalar type.
For the first parameter (point), the type of the first expression (object expression) must be a "class object" (full type).
This is a misnomer because it does not eliminate ambiguity at all. It should use "can only", and compilers interpret it that way. This is mainly due to historical reasons, as recently a committee member recently told me to fall asleep. See Rules for the Design and Compilation of International Standards , Appendix H.