2010-11-19 8 views
3

mit einer .h-Datei gegeben, die ich habe in letzter Zeit auf einem kleinen Projekt zu arbeiten, und ich konnte nicht herausfinden, etwas ..Wann sollte ich das Stichwort „Typname“ verwenden, wenn Vorlagen

Ich habe enthielt eine Klasse mit einer typenspezifischen Vorlage. In dieser Klasse gab es eine Privatklasse.

template <typename T> 
class Something 
{ 
public: 
     Something(); 
     ~Something(); 

     Node* Function1(int index); 
     int Index(const T& id); 


private: 
     class Node() 
     { 
       public: 
       T id; 

       //Imagine the rest for the Node 


     };  
}; 

Das Problem ist aufgetreten, wenn ich die Funktionen der Klasse "Something"

Hier ist, wie ich es tat (in einer .inl Datei)

template<typename T> 
Node* Something::Function1(int index) //Is the return type well written? 
{ 
     // returns the node at the specified index 
} 

template<typename T> 
int Something::Index(const T& id) //Is the parameter type well specified? 
{ 
     // returns the index of the node with the specified id 
} 

So ist die abhör definieren wollte Teil war im Definitionsteil ... Muss ich dem Compiler mitteilen, dass der Rückgabetyp (in diesem Fall Knoten *) die Typname-Vorlage verwendet (wie diese: typename Node*)? Und was ist mit dem Parameter? typename const Node&?

Also im Grunde, wann muss ich angeben, ob die Funktion/der Parameter eine Vorlage verwendet?

Danke für Ihre Zeit.

+0

Bitte sende Sinpets in deine Frage! – mmmmmmmm

+0

Ich habe Links mit Snippets gepostet. Ich konnte nicht herausfinden, wie ich meine Snippets richtig einrücken kann. – Pacane

Antwort

2
template<typename T> 
typename Something<T>::Node * Something::Function1(int index) //Is the return type well written? 
{ 
     // returns the node at the specified index 
} 
+0

Ok, und was ist mit dem Parametertyp der anderen Methode? – Pacane

+3

'Node' ist ein verschachtelter Klassenname. Sie können es also nicht verwenden, es sei denn, Sie verwenden Code für eine Methode von 'Something ' oder Sie verwenden den vollständigen Typnamen Something :: Node' name. Und ein Methodenrückgabetyp (außerhalb der Klasse definiert) ist noch nicht "in" einer Methode von "Something", so dass Sie dies dem Compiler klar machen müssen. Die andere Methode wird dieses Problem nicht haben, da der Compiler immer weiß, was "int" bedeutet. – aschepler

+0

Danke für die Erklärung und für die Zeit. – Pacane

3

Die einfache Regel: Sie benötigen das typename Schlüsselwort, das Sie einen Typnamen mit der Class::Type Syntax jedes Mal verwenden, wenn der Class Teil auf einem Template-Parametern abhängig ist. (Der Class Teil könnte ein Vorlagenparameter sein oder ein typedef in Ihrer Klassenvorlage usw.)

Edit: Es gibt auch einige Verwirrung über geschachtelte Klassenbereichsregeln. Dies ist größtenteils unabhängig von dem typename Problem, also hier ist ein Beispiel ohne Vorlage.

class Outer { 
public: 
    class Inner { 
    }; 
    Inner* func(Inner* obj); 
}; 

Outer::Inner* func(Inner* obj) 
{ 
} 

Der vollständige Name von Inner ist Outer::Inner. Sie können aber auch den kürzeren Namen Inner überall im Bereich der Klasse Outer verwenden, einschließlich aller Deklarationen von func. Bei der Definition von func ist der Rückgabetyp NICHT im Bereich Outer, daher ist der vollständige Name erforderlich. Aber nach der (, sind die Funktionsparameter im Bereich Outer, so ist der kurze Name in Ordnung.

dies mit dem Template-ness des ursprünglichen Beispiel kombinierend, da das Äquivalent von OuterSomething<T> ist, müssen Sie die typename Schlüsselwort Something<T>::Node zu sagen.

+0

Also sollte der Parametertyp in der Definition der Funktion Index geschrieben werden typenname const Klasse :: Knoten & id? – Pacane

+1

@Pacane: Das hängt davon ab, ob Sie ein 'T' oder ein' Node' übergeben möchten. Wenn Sie einen 'Node' übergeben wollen, wird die Vollversion funktionieren, wird aber nicht benötigt, da der Compiler gerade gesehen hat, dass Sie eine' Something' Methode definieren, und 'const Node &' wäre in Ordnung. – aschepler

+0

Danke für die Erklärung und für die Zeit. – Pacane

5

Für Function1 müssen Sie dem Compiler mitteilen, welcher Knoten ist - in diesem Fall ist es ein verschachtelter Typ innerhalb Something<T>. Da es von T abhängig ist (es ist ein abhängiger Name), müssen Sie dem Compiler mitteilen, dass es sich um einen Typ handelt, also müssen Sie ihn als typename Something<T>::Node schreiben. Das Problem ist, dass es möglicherweise einige T für die ist nicht eigentlich ein Typ (d. H. Wenn Sie teilweise spezialisieren Something<T>).

Für Index, was Sie haben, ist in Ordnung - const T& ist nur ein Verweis auf eine const T, und der Compiler weiß, was T ist.

+0

Wenn also der Parameter ein Zeiger auf einen Knoten wäre, müsste ich den Typnamen erneut eingeben, richtig? – Pacane

+1

Da Sie sich in 'Something ' befinden, könnten Sie einfach 'Node *' schreiben. Aber wenn Sie es explizit ausgeschrieben haben, müssten Sie 'typename Something :: Node *' anstatt nur 'Something :: Node *' sagen. –

+0

Danke für die Erklärung und für die Zeit. – Pacane

1

typename und class sind gleichwertig in Parameterliste Vorlagentyp:

template <class T> class C; 

ist die gleiche wie

template <typename T> class C; 

Wo die typename erforderlich ist, wenn es um dependent names:

template <typename T> struct A { 
    typedef typename T::some_type container; 
}; 
+2

Eigentlich sind Typname und Klasse in einer Parameterliste NICHT gleichwertig. Das Schlüsselwort typename kann "class" nicht ersetzen, wenn Vorlagenparameter erwartet werden. –

+0

Ja, danke, habe das vergessen. Obwohl es nur ein boo-boo seitens der Sprache ist - sie haben nur vergessen, dass der Fall genauso ist wie ich hier :) –

Verwandte Themen