Ich weiß, dass die Schlüsselwörter typename
und class
in Vorlagenargumenten austauschbar sind, aber ich dachte, dass nur typename
für die Spezifikation verschachtelter Klassen erlaubt ist.
Ich habe versehentlich versehentlich " class
" anstelle von " typename
" für eine verschachtelte Klasse geschrieben.
Und ich fand heraus, dass gcc auch dort class
akzeptiert, also kannst du etwas schreiben wie:
in Ihrer Vorlage.
Ist das ein GCC-Bug oder erlaubt der Standard wirklich diese Syntax?
UPDATE: Beispiel für Code:
%Vor% class a::b
ist ein ausgearbeiteter Typspezifizierer. Die Namenssuche nach einem ausgearbeiteten Typspezifizierer ignoriert Nicht-Typnamen. Wenn Sie also eine Vorlage analysieren, können Sie zwei Dinge annehmen:
b
suchen, gibt uns entweder name lookup einen Typ oder es gibt einen Fehler aus (findet keinen Namen). Aus diesem Grund benötigt class a::b
in C ++ 0x nicht typename
(Sie können es sowieso nirgends in einen elaborierten Typspezifizierer einfügen). C ++ 03 erlaubt das nicht, daher scheint GCC die C ++ 0x-Regeln als Erweiterung zu implementieren.
Das ist nicht besonders schlimm. Jeder echte Compiler implementiert Regeln, die in ihrer C ++ 03-Version für sie sinnvoll und einfach zu implementieren sind, selbst wenn sie formell abgelehnt werden müssten. % Co_de% muss jedoch nach einem Klassennamen suchen. Wenn es sich lediglich um einen Typedef handelt, ist die Suche nach dem Typspezifizierer ungültig.
Beachten Sie, dass class a::b
die einzige Möglichkeit ist, Nicht-Typ-Namen in einem Lookup zu ignorieren (außer für obskure Fälle wie vor einem class a::b
in einem qualifizierten Namen, die ähnliche spezielle Regeln haben). Zum Beispiel
Wenn Sie nach C ++ 0x kompilieren und ::
verwenden, wird der Code gültig, weil class T::type t;
den Datenmember ignoriert, aber die verschachtelte Klasse findet.
Abschnitt 14.6 ("Namensauflösung") in ISO 14886: 2003 scheint die Definition dafür zu sein, wie das funktionieren soll. Absatz 3 sagt:
Eine qualifizierte-ID , die auf einen Typ verweist und in der der verschachtelte Name-Specifier von einem Template-Parameter abhängt (14.6 .2) muss das Schlüsselwort
typename
vorangestellt werden, um anzuzeigen, dass die qualifizierte ID einen Typ bezeichnet, der einen elaborierten Typ-Spezifizierer (7.1.5.3) bildet.
Keine Erwähnung des Schlüsselworts class
. Ich denke, das ist ein GCC-Bug.
Es kann nicht mit Comeau Online (Comeau C / C ++ 4.3.10.1 (6. Oktober 2008 11:28:09)) kompiliert werden, so dass mindestens einer der beiden Compiler einen Fehler hat.
%Vor%Sicherlich scheint der Standard zu bestätigen, dass typename verwendet werden sollte. Ab 14.6 / 2:
Ein in einer Schablonendeklaration oder -definition verwendeter Name, der von einem Schablonenparameter abhängig ist, wird davon ausgegangen, keinen Typ zu nennen, es sei denn, die anwendbare Namenssuche findet einen Typnamen oder der Name wird durch das Schlüsselwort typename qualifiziert.
Ideone zeigt eine nette Fehlermeldung, wenn der abhängige Name nicht in eine Klasse aufgelöst wird. Ihr Beispiel funktioniert also nur, weil iterator
tatsächlich ein class
ist. :)
Bearbeiten : MSVC kann nicht kompiliert werden, selbst wenn das abhängige Objekt tatsächlich eine Klasse ist,
Fehler C2242 : typedef name kann der Klasse nicht folgen / struct / union
Bearbeiten 2 : Dies scheint ein MSVC-Bug zu sein, da g ++ und Comeau online gut kompilieren, wenn der abhängige Name eine Klasse ist.
Ich bin immer noch verloren, was passiert. Ich würde einen Kommentar abgeben, wenn es nicht problematisch wäre, dort Code zu schreiben.
%Vor%kompiliert nicht mit gcc mit einem Fehler während der Instanziierung. Es wird kompiliert, wenn X :: bb eine Klasse ist. Como hat das gleiche Verhalten.
Edit, ich denke, ich verstehe jetzt besser.
%Vor%ist ein elaborierter Klassenspezifizierer. Foo :: Bar wird als qualifizierter Name nachgeschlagen (3.4.4 / 3). Da es abhängig ist, muss das Nachschlagen in der zweiten Phase während der Instanziierung durchgeführt werden. Dann, wenn es nicht gefunden wird oder wenn es kein Klassenname oder Enum-Name ist, ist der elaborated-class-specifier schlecht gebildet.
TL; DR g ++ scheint keinen Fehler zu haben.