Ich habe eine Weile mit Clang gespielt und bin auf "test / SemaTemplate / Dependent-Template-Recovery.cpp" (in der Clang-Distribution) gestoßen, das Hinweise zur Wiederherstellung nach einem Vorlagenfehler geben soll.
Das Ganze lässt sich leicht auf ein minimales Beispiel reduzieren:
template<typename T, typename U, int N> struct X {
void f(T* t)
{
// expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}
t->f0<U>();
}
};
Die Fehlermeldung von clang:
tpl.cpp:6:13: error: use 'template' keyword to treat 'f0' as a dependent template name
t->f0<U>();
^
template
1 error generated.
... Aber es fällt mir schwer zu verstehen, wo genau man das template
Schlüsselwort einfügen soll , damit der Code syntaktisch korrekt ist?
Antworten:
ISO C ++ 03 14.2 / 4:
In
t->f0<U>();
f0<U>
ist eine Mitgliedervorlagenspezialisierung, die nach angezeigt wird->
und explizit vom Vorlagenparameter abhängt.U
Daher muss der Mitgliedervorlagenspezialisierung dastemplate
Schlüsselwort vorangestellt werden .Also wechseln Sie
t->f0<U>()
zut->template f0<U>()
.quelle
t->(f0<U>())
hätte das behoben, da ich dachte, dass diesf0<U>()
in einen eigenständigen Ausdruck umgewandelt werden würde ... nun, ich dachte falsch, es scheint ...Beachten Sie zusätzlich zu den Punkten, die andere angesprochen haben, dass sich der Compiler manchmal nicht entscheiden konnte und beide Interpretationen beim Instanziieren zu alternativen gültigen Programmen führen können
Dies wird gedruckt,
0
wenn Sie estemplate
vorher weglassen,f<int()>
aber1
wenn Sie es einfügen. Ich lasse es als Übung, um herauszufinden, was der Code tut.quelle
f<U>
immer auf und druckt immer1
, was für mich absolut sinnvoll ist. Ich verstehe immer noch nicht, warum dastemplate
Schlüsselwort erforderlich ist und welchen Unterschied es macht.template
erforderlich ist: stackoverflow.com/questions/610245/…, ohne sich ausschließlich auf schwer verständliche Standardbegriffe zu verlassen. Bitte melden Sie, wenn etwas in dieser Antwort noch verwirrend ist.Fügen Sie es kurz vor dem Punkt ein, an dem sich das Caret befindet:
Bearbeiten: Der Grund für diese Regel wird klarer, wenn Sie wie ein Compiler denken.
Compiler blicken im Allgemeinen nur auf ein oder zwei Token gleichzeitig und nicht auf den Rest des Ausdrucks.[Bearbeiten: siehe Kommentar] Der Grund für das Schlüsselwort ist derselbe, warum Sie dastypename
Schlüsselwort benötigen , um abhängige Typnamen anzugeben: Es sagt dem Compiler: "Hey, die Kennung, die Sie sehen werden, ist der Name einer Vorlage und nicht der Name eines statischen Datenelements, gefolgt von einem Vorzeichen ".quelle
template
. Es gibt Fälle, in denen sowohl mit als auch ohnetemplate
gültige Programme mit unterschiedlichem Verhalten angezeigt werden. Dies ist also nicht nur ein syntaktisches Problem (t->f0<int()>(0)
gilt syntaktisch sowohl für die Version als auch für die Liste der Vorlagenargumentlisten).Auszug aus C ++ - Vorlagen
Das .template-Konstrukt Ein sehr ähnliches Problem wurde nach der Einführung des Typnamens entdeckt. Betrachten Sie das folgende Beispiel mit dem Standard-Bitset-Typ:
Das seltsame Konstrukt in diesem Beispiel ist .template. Ohne diese zusätzliche Verwendung der Vorlage weiß der Compiler nicht, dass das folgende Token (<) nicht wirklich "kleiner als" ist, sondern der Anfang einer Vorlagenargumentliste. Beachten Sie, dass dies nur dann ein Problem ist, wenn das Konstrukt vor dem Zeitraum von einem Vorlagenparameter abhängt. In unserem Beispiel hängt der Parameter bs vom Vorlagenparameter N ab.
Zusammenfassend sollte die .template-Notation (und ähnliche Notationen wie -> template) nur innerhalb von Templates verwendet werden und nur, wenn sie etwas folgen, das von einem Template-Parameter abhängt.
quelle