3 Stimmen

Warum ist die Verwendung von typedef in dieser Vorlage notwendig?

Wenn ich diesen Code in Visual Studio 2005 kompiliere:

  template <class T>
  class CFooVector : public std::vector<CFoo<T>>
  {
  public:
    void SetToFirst( typename std::vector<CFoo<T>>::iterator & iter );
  };

  template <class T>
  void CFooVector<T>::SetToFirst( typename std::vector<CFoo<T>>::iterator & iter )
  {
    iter = begin();
  }

Ich erhalte diese Fehler:

c:\home\code\scantest\stltest1\stltest1.cpp(33) : error C2244:     'CFooVector<T>::SetToFirst' : unable to match function definition to an existing declaration
    c:\home\code\scantest\stltest1\stltest1.cpp(26) : see declaration of 'CFooVector<T>::SetToFirst'
    definition
    'void CFooVector<T>::SetToFirst(std::vector<CFoo<T>>::iterator &)'
    existing declarations
    'void CFooVector<T>::SetToFirst(std::_Vector_iterator<_Ty,_Alloc::rebind<_Ty>::other> &)'

Wenn ich der CFooVector-Vorlage ein Typedef hinzufüge, kann ich den Code kompilieren und funktionieren lassen:

  template <class T>
  class CFooVector : public std::vector<CFoo<T>>
  {
  public:
    typedef typename std::vector<CFoo<T>>::iterator FooVIter;
    void SetToFirst( FooVIter & iter );
  };

  template <class T>
  void CFooVector<T>::SetToFirst( FooVIter & iter )
  {
    iter = begin();
  }

Meine Frage ist, warum funktioniert die typedef Arbeit, wenn Sie die bloße 'typename std::vector>::iterator' Erklärung nicht funktioniert hat?

5voto

Eugene Punkte 6941

Dies kompiliert auch und offenbart die Quelle der VC++ Verwirrung - Allokator Typ. Anscheinend wählt VS außerhalb der Klasse einen anderen Standard. Oder vielleicht kann es nicht erkennen, dass sie die gleichen sind.

Kompiliert auf VS2008 (wie ist) und VS2003 (mit Leerzeichen zwischen >>)

template <class T>
class CFoo
{
public:
    T m_t;
};

template <class T>
class CFooVector : public std::vector<CFoo<T>>
{
public:
    void SetToFirst(typename std::vector<CFoo<T>, typename CFooVector::_Alloc>::iterator & iter);

};

template <class T>
void CFooVector<T>::SetToFirst( typename std::vector<CFoo<T>, typename CFooVector::_Alloc>::iterator & iter )
{
    iter = begin();
}

GCC 3.4 wollte this->begin() und Raum, aber sonst kann es den Code ohne explizite Allokator Typ kompilieren... Sieht definitiv so aus, als wäre der MS-Compiler nicht so schlau wie er sein sollte...

2voto

jalf Punkte 235501

Die Frage bezieht sich nicht wirklich auf typedef, sondern auf typename.

Wann immer der Compiler auf einen Namen stößt, der von einer Vorlage abhängig ist (im Grunde alles, was mit :: nach einer Schablone ist es nicht in der Lage festzustellen, ob es sich um einen Typ oder einen Wert handelt (es könnte z. B. ein statischer int sein), daher benötigt es einen Hinweis.

Wenn Sie Folgendes hinzufügen typename geben Sie an, dass das abhängige Mitglied tatsächlich ein Typ ist.

In Ihrem typedef-Beispiel haben Sie noch den typename in der typedef-Deklaration, aber sobald der typedef deklariert ist, ist das kein abhängiger Name mehr. Es ist einfach ein Typ, so dass die typename ist nicht notwendig, wenn man sich auf den Typedef bezieht.

Im Grunde kann der Compiler nicht sicher sein, dass std::vector<CFoo<T>>::iterator ist ein Typ.

Aber sie weiß, dass FooVIter ist ein Typ, weil es ein Typedef ist. Typedefs sind immer Typen.

1voto

Juan Punkte 3458

Typename ist hier das wichtigste Schlüsselwort.

Es ist wichtig zu beachten:

>>

sollte ein Leerzeichen dazwischen stehen, um den Compiler nicht zu verwirren, so dass er denkt, Sie verwenden

operator>>

Ohne Ihren gesamten Code, weiß ich nicht, warum es ein Problem nach der Verwendung von typename gibt. Vielleicht brauchen Sie es nicht in der Definition außerhalb der Klassendefinition?

Es könnte auch besser sein, dies zu tun:

template <typename T>

anstelle von

template <class T>

Übrigens ist es keine gute Idee, von STL-Klassen abzuleiten, es sei denn, Sie sind sehr, sehr vorsichtig.

STL-Klassen haben keine virtuellen Destruktoren.

0voto

Vishesh Handa Punkte 1721

Scheint bei mir gut zu funktionieren wenn Ich nehme die folgenden Änderungen vor -

template <class T>
class CFoo
{
public:
T m_t;
};

template <class T>
class CFooVector : public std::vector< CFoo<T> >
{
public:
void SetToFirst( typename std::vector<CFoo<T> >::iterator & iter );
};

template <class T>
void CFooVector<T>::SetToFirst( typename std::vector<CFoo<T> >::iterator & iter )
{
iter = begin();
}

Ich habe grundsätzlich die std::vector<CFoo<T>> à std::vector<CFoo<T> > denn sonst erkennt der Compiler (in meinem Fall gcc) es als den >>-Operator.

0voto

Michael Burr Punkte 320591

Ein weiterer interessanter Aspekt: VS2008 kompiliert Ihren zweiten Versuch, wenn Sie nicht die std:: Namensqualifikation auf der vector in der Definition von SetToFirst() :

  template <class T>
  class CFooVector : public std::vector< CFoo<T> >
  {
  public:
      void SetToFirst( typename std::vector< CFoo<T> >::iterator & iter );
  };

  template <class T>
  void CFooVector<T>::SetToFirst( typename /*std::*/vector< CFoo<T> >::iterator & iter )
  {
    iter = begin();
  };

Beachten Sie, dass dies nur bei der Definition, nicht aber bei der Deklaration eine Rolle zu spielen scheint. Interessant war für mich auch, dass es keine Rolle spielte, ob es ein " using namespace std; " oder nicht...

Ich weiß nicht so recht, was ich davon halten soll.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X