Die Kurzfassung, die Sie tun müssen typename X::Y
immer dann, wenn X ein Schablonenparameter ist oder von ihm abhängt. Solange X nicht bekannt ist, kann der Compiler nicht sagen, ob Y ein Typ oder ein Wert ist. Sie müssen also Folgendes hinzufügen typename
um anzugeben, dass es ein Typ ist.
Zum Beispiel:
template <typename T>
struct Foo {
typename T::some_type x; // T is a template parameter. `some_type` may or may not exist depending on what type T is.
};
template <typename T>
struct Foo {
typename some_template<T>::some_type x; // `some_template` may or may not have a `some_type` member, depending on which specialization is used when it is instantiated for type `T`
};
Wie sbi in den Kommentaren anmerkt, liegt die Ursache für diese Unklarheit darin, dass Y
kann ein statisches Mitglied, ein Enum oder eine Funktion sein. Ohne Kenntnis des Typs von X
können wir nicht sagen. Der Standard legt fest, dass der Compiler davon ausgehen sollte, dass es sich um einen Wert handelt, es sei denn, er wird explizit als Typ gekennzeichnet, indem er die typename
Stichwort.
Und es scheint, als wollten die Kommentatoren wirklich, dass ich auch einen anderen Fall erwähne, der damit zusammenhängt: ;)
Wenn der abhängige Name eine Funktionsschablone ist und Sie sie mit einem expliziten Schablonenargument aufrufen ( foo.bar<int>()
zum Beispiel), müssen Sie die template
Schlüsselwort vor dem Funktionsnamen, wie in foo.template bar<int>()
.
Der Grund dafür ist, dass der Compiler ohne das Schlüsselwort template davon ausgeht, dass bar
ein Wert ist und Sie den Kleiner-als-Operator aufrufen möchten ( operator<
) darauf.