Gelegentlich habe ich einige wirklich nicht entzifferbare Fehlermeldungen gesehen, die gcc
bei der Verwendung von Vorlagen ausgegeben wurden ... Insbesondere hatte ich Probleme, bei denen scheinbar korrekte Deklarationen sehr seltsame Kompilierungsfehler verursachten, die auf magische Weise behoben wurden, indem das typename
Schlüsselwort dem Anfang des vorangestellt wurde Deklaration ... (Zum Beispiel habe ich erst letzte Woche zwei Iteratoren als Mitglieder einer anderen Klasse mit Vorlagen deklariert und musste dies tun) ...
Worum geht es in der Geschichte typename
?
Antworten:
Es folgt das Zitat aus Josuttis Buch:
quelle
typename
(wenn auch nicht alle!).Stan Lippmans BLog-Post schlägt vor:
Grundsätzlich hat Stroustrup das Klassenschlüsselwort wiederverwendet, ohne ein neues Schlüsselwort einzuführen, das anschließend aus den folgenden Gründen im Standard geändert wird
Als Beispiel gegeben
Sprachgrammatik interpretiert falsch
T::A *aObj;
als arithmetischer Ausdruck, so dass ein neues Schlüsselwort namens eingeführt wirdtypename
Es weist den Compiler an, die nachfolgende Anweisung als Deklaration zu behandeln.
Deshalb haben wir beide
Sie können sich diesen Beitrag ansehen , er wird Ihnen auf jeden Fall helfen. Ich habe nur so viel wie möglich daraus extrahiert
quelle
typename
erforderlich, wenn Sie das vorhandene Schlüsselwortclass
für denselben Zweck verwenden konnten?typename
wurde notwendig, um das Parsing-Problem zu beheben, wie in Naveens Antwort beschrieben, indem Josuttis zitiert wurde. (Ich glaube nicht, dass das Einfügen einesclass
an dieser Stelle funktioniert hätte.) Erst nachdem das neue Schlüsselwort für diesen Fall akzeptiert wurde, war es auch in Deklarationen von Vorlagenargumenten zulässig ( oder sind das Definitionen? ), Daclass
es immer etwas gegeben hat irreführend.Betrachten Sie den Code
Leider muss der Compiler nicht psychisch sein und weiß nicht, ob sich T :: sometype auf einen Typnamen oder ein statisches Mitglied von T bezieht. Man
typename
sagt es also:quelle
In einigen Situationen, in denen Sie auf ein Mitglied des sogenannten abhängigen Typs verweisen (was "abhängig vom Vorlagenparameter" bedeutet), kann der Compiler die semantische Bedeutung des resultierenden Konstrukts nicht immer eindeutig ableiten, da er nicht weiß, um welche Art von Namen es sich handelt (dh ob es sich um einen Namen eines Typs, einen Namen eines Datenelements oder einen Namen eines anderen handelt). In solchen Fällen müssen Sie die Situation eindeutig definieren, indem Sie dem Compiler explizit mitteilen, dass der Name zu einem Typnamen gehört, der als Mitglied dieses abhängigen Typs definiert ist.
Beispielsweise
In diesem Beispiel ist das Schlüsselwort
typename
erforderlich, damit der Code kompiliert werden kann.Dasselbe passiert, wenn Sie auf ein Vorlagenmitglied vom abhängigen Typ verweisen möchten, dh auf einen Namen, der eine Vorlage kennzeichnet. Sie müssen dem Compiler auch helfen, indem Sie das Schlüsselwort verwenden
template
, obwohl es anders platziert istIn einigen Fällen kann es erforderlich sein, beide zu verwenden
(wenn ich die Syntax richtig verstanden habe).
Natürlich soll eine andere Rolle des Schlüsselworts
typename
in Vorlagenparameterdeklarationen verwendet werden.quelle
Das Geheimnis liegt in der Tatsache, dass eine Vorlage für einige Typen spezialisiert werden kann. Dies bedeutet, dass die Schnittstelle für verschiedene Typen völlig unterschiedlich definiert werden kann. Zum Beispiel können Sie schreiben:
Man könnte fragen, warum dies nützlich ist und in der Tat: Das sieht wirklich nutzlos aus. Beachten Sie jedoch, dass
std::vector<bool>
derreference
Typ beispielsweise völlig anders aussieht als bei anderenT
s. Zugegeben, es ändert nicht die Art vonreference
Typ zu etwas anderem, aber es könnte trotzdem passieren.Was passiert nun, wenn Sie mit dieser
test
Vorlage eigene Vorlagen schreiben? Etwas wie dasEs scheint für Sie in Ordnung zu sein, weil Sie erwarten, dass dies
test<T>::ptr
ein Typ ist. Aber der Compiler weiß es nicht und in der Tat wird ihm vom Standard sogar geraten, das Gegenteil zu erwarten, estest<T>::ptr
ist kein Typ. Um dem Compiler mitzuteilen, was Sie erwarten, müssen Sie zuvor ein hinzufügentypename
. Die richtige Vorlage sieht so ausFazit: Sie müssen
typename
vorher hinzufügen, wann immer Sie einen verschachtelten Typ einer Vorlage in Ihren Vorlagen verwenden. (Natürlich nur, wenn ein Vorlagenparameter Ihrer Vorlage für diese innere Vorlage verwendet wird.)quelle
Zwei Anwendungen:
template
Argument Schlüsselwort (anstelle vonclass
)typename
Schlüsselwort teilt dem Compiler mit, dass ein Bezeichner ein Typ ist (und keine statische Elementvariable).quelle
Ich denke, alle Antworten haben erwähnt, dass das
typename
Schlüsselwort in zwei verschiedenen Fällen verwendet wird:a) Beim Deklarieren eines Vorlagentypparameters. z.B
Was es keinen Unterschied zwischen ihnen gibt und sie genau gleich sind.
b) Bevor Sie einen verschachtelten abhängigen Typnamen für eine Vorlage verwenden.
Was nicht verwendet wird,
typename
führt zu Analyse- / Kompilierungsfehlern.Was ich dem zweiten Fall hinzufügen möchte, wie in Scot Meyers Buch Effective C ++ erwähnt , ist, dass es eine Ausnahme gibt,
typename
vor einem verschachtelten abhängigen Typnamen zu verwenden . Die Ausnahme besteht darin, dass Sie den verschachtelten abhängigen Typnamen entweder als Basisklasse oder in einer Elementinitialisierungsliste nicht verwendentypename
sollten:Hinweis: Die Verwendung
typename
für den zweiten Fall (dh vor dem Namen des verschachtelten abhängigen Typs) ist seit C ++ 20 nicht mehr erforderlich.quelle
quelle