2009-07-14 17 views
13
template<class T> 
class Set 
{ 
public: 
    void insert(const T& item); 
    void remove(const T& item); 
private: 
    std::list<T> rep; 
} 

template<typename T> 
void Set<T>::remove(const T& item) 
{ 
    typename std::list<T>::iterator it = // question here 
    std::find(rep.begin(),rep.end(),itme); 
    if(it!=rep.end()) rep.erase(it); 

} 

Warum wird der Typname in der remove() benötigt?Warum brauchen wir hier typename?

+0

Vielleicht bearbeiten, um klarer zu machen, dass die Zeile, über die Sie sprechen, typenname ist std :: list :: iterator it = std :: finden (rep.begin(), rep.end(), itme); Ich denke, das ist deine Absicht. – aem

Antwort

18

Im Allgemeinen C++ typename muss wegen der unglücklichen Syntax [*] es erbt von C, die es unmöglich, ohne nicht-lokalen Informationen machen zu sagen - zum Beispiel - in A * B; ob A Namen einen Typ (in der Fall ist dies eine Deklaration von B als Zeiger darauf) oder nicht (in diesem Fall ist dies ein Multiplikationsausdruck - durchaus möglich, da A, für alles, was Sie ohne nicht-lokale Informationen sagen können, könnte eine Instanz einer Klasse sein Überlasten operator* etwas komisches zu tun ;-). In den meisten Fällen verfügt der Compiler über die nicht-lokalen Informationen, die zur Disambiguierung erforderlich sind (obwohl die unglückliche Syntax immer noch bedeutet, dass der Low-Level-Parser Feedback von der übergeordneten Ebene benötigt, die die Symboltabelleninformationen enthält) ... aber mit Templates tut es das nicht (nicht generell, obwohl es in diesem speziellen Fall technisch illegal wäre, std::list<T> zu spezialisieren, so dass sein ::iterator KEIN Typname ist ;-).

[*] Nicht nur meine Meinung, sondern auch die Meinung von Ken Thompson und Rob Pikes, derzeit meine Kollegen, die sich mit der Entwicklung und Implementierung einer neuen Programmiersprache für den internen Gebrauch beschäftigen: diese neue Programmiersprache, während ihre Syntax ist Meistens C-like, wiederholt Cs Syntax-Designfehler NICHT - es ist die neue Sprache (wie zB im guten alten Pascal), Syntax reicht aus, um Bezeichner zu unterscheiden, die einen Typ aus denen benennen müssen, die nicht müssen ;-).

+1

Iterator könnte möglicherweise eine statische Elementvariable sein. Und der Compiler nimmt das standardmäßig an. Also der Compilerfehler. –

+0

Ich nehme an, dass die Bestätigung, ob die Sprache "B ++" heißt oder nicht, eine schwerwiegende Verletzung des Geschäftsgeheimnisses wäre. ;-) –

+0

Tut mir leid, dass ich das von den Toten zurückbringe, aber 8 Jahre später bin ich neugierig, ob es noch weitere Informationen über diese Programmiersprache gibt. Obwohl ich nicht die Luft halte. – Cebtenzzre

0

Ich denke im Allgemeinen brauchen Sie sowohl den Typ/Klasse T in der Klassendeklaration als auch Funktionsdefinitionen, weil Sie vollständige/teilweise Vorlage Spezifikationen für Funktionsdefinitionen definieren können. Ie. Sie könnten Ihre Remove-Funktion für Ints, Strings, was auch immer es ist, spezialisieren. In diesem Fall sagen Sie dem Compiler "Dies ist die allgemeine Vorlage für jeden Typ" und später definieren Sie möglicherweise dieselbe Funktion, die nur für Ganzzahlen angegeben wurde.

+0

Ahh diese Antwort ist ungültig mit dieser Klarstellung, sorry! – DeusAduro

12

Wenn Sie sprechen von typename verwendet mit std::list<T>::iterator:

Der Typname verwendet wird, um klarzustellen, dass iterator eine Art innerhalb der Klasse std::list<T> definiert ist. Ohne Typname wird std::list<T>::iterator als statisches Element betrachtet. typename wird verwendet, wenn ein Name, der von einem Vorlagenparameter abhängt, ein Typ ist.

+0

+1 Erstaunliche Erklärung! – AraK

1

Typname wird in Ihrer Deklaration von 'it' benötigt, da der Compiler ansonsten nicht weiß, dass es sich um eine Typdeklaration und nicht um einen Ausdruck handelt.

Gemäß this page, "Verwenden Sie das Schlüsselwort typename, wenn Sie einen qualifizierten Namen haben, der sich auf einen Typ bezieht und von einem Vorlagenparameter abhängt."