Ich glaube nicht, dass diese schlecht geformt sind. Zuerst wird nach using X::f2
, X
gesucht, und dies ergibt eindeutig die Klassenart X
. Dann wird f2
in X
nachgeschlagen, und das ist auch eindeutig (es wird nicht in D
nachgeschlagen!).
Der zweite Fall funktioniert aus dem gleichen Grund.
Aber wenn Sie Anruff2
auf einem D
Objekt, wird der Anruf nicht eindeutig sein, da der Name f2
in allen Subobjekte von D
vom Typ X
nachgeschlagen und D
hat zwei solche Teilobjekte und f2
ist ein nicht -statische Elementfunktion Derselbe Grund gilt für den zweiten Fall. Es macht keinen Unterschied, ob Sie f3
mit Z::X
oder X
direkt nennen. Beide bezeichnen die Klasse X
.
Um eine Mehrdeutigkeit für die Verwendungserklärung zu erhalten, müssen Sie es anders schreiben. Beachten Sie, dass in C++ 0x using ThisClass::...;
nicht gültig ist. Es ist jedoch in C++ 03, solange sich der gesamte Name auf ein Basisklassenmitglied bezieht.
Umgekehrt, wenn dies in C++ 0x erlaubt wäre, die ganze Erklärung auch mit gültig wäre, weil C++ 0x nicht Subobjekte berücksichtigt für Name-Nachschlag nehmen: D::f2
bezieht sich eindeutig auf nur eine Erklärung (die in X
). Siehe DR #39 und die Abschlussarbeit 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;
};
Die C++ 03 Norm beschreibt dies in den Absätzen 10.2
und 3.4.3.1
.
Antwort für Edit3:
Ja, GCC und VS2010 falsch ist. trouble
bezieht sich auf den Typ, der durch den Namen der eingefügten Klasse ::trouble
und die verschachtelte Klasse Y::trouble
gefunden wird. Der Name trouble
vor dem ::
wird mit unqualifizierten Lookup (von 3.4.1/7
, die an 10.2
im ersten Aufzählungszeichen delegiert) Nachschlagen aller Objekt, Funktion und Enumerator-Namen (3.4.3/1
- es gibt jedoch keine solche Namen in diesem Fall) nachgeschlagen. Es verletzt dann gegen 10.2
‚s Anforderung, dass:
If the resulting set of declarations are not all from sub-objects of the same type ... the program is ill-formed.
Es ist möglich, dass VS2010 und GCC anders als Comeau C++ 0x Formulierung interpretieren und rückwirkend diese Formulierung implementieren:
In a using-declaration used as a member-declaration, the nested-name-specifier shall name a base class of the class being defined.
Diese bedeutet, dass Nicht-Basisklassen berücksichtigt werden, aber es ist ein Fehler, wenn eine Nicht-Basisklasse benannt wird. Wenn der Standard beabsichtigen würde, Nicht-Basisklassennamen zu ignorieren, würde es sagen kann nur hier, oder buchstabieren Sie es explizit (beide Praktiken sind getan). Der Standard ist jedoch in keiner Weise mit seiner Verwendung von soll und kann. Und GCC implementiert C++ 0x-Formulierung, weil es sonst völlig fehlerfreien C++ 03-Code zurückweist, nur weil die using-Deklaration seinen Klassennamen enthält.
Ein Beispiel für die unklare Formulierung, betrachten den folgenden Ausdruck:
a.~A();
Dies ist syntaktisch mehrdeutig, weil es ein Mitglied Funktionsaufruf sein kann, wenn a
ein Klassenobjekt ist, aber es kann ein Pseudo sein -destructor-call (was ein No-Op ist), wenn a
einen Skalartyp hat (wie int
). Aber was die Norm sagt, ist für die Syntax eines pseudo-Destruktoraufrufs und Klassenmitglied Zugriff auf 5.2.4
und 5.2.5
jeweils
The left-hand side of the dot operator shall be of scalar type.
For the first option (dot) the type of the first expression (the object expression) shall be “class object” (of a complete type).
, dass die falsche Verwendung ist, weil es nicht die Mehrdeutigkeit überhaupt nicht aufklären. Es sollte "kann nur" verwenden, und Compiler interpretieren es auf diese Weise. Das hat hauptsächlich historische Gründe, wie mir ein Komitee-Mitglied kürzlich im Usenet erzählt hat. Siehe The rules for the structure and drafting of International Standards, Anhang H.
In D fügen Sie eine Methode hinzu, die f2() aufruft, um zu sehen, was passiert. –