Funktionstemplate: Wo ist der Fehler?

jokey2

Erfahrenes Mitglied
Hallo Gemenide!

Ich habe hier ein Problem mit einem Funktionstemplate. Folgendes Template läßt sich problemlos kompilieren:
Code:
template<typename T_ListElement>
  T_ListElement *  // Rückgabewert: Zeiger auf T_ListElement
  FindInList
  (const std::list<T_ListElement> &searchlist,
  const T_ListElement &Element)
{
  std::list<T_ListElement>::iterator it = searchlist.begin();
       
  while(it != searchlist.end())
  {
    if(Element == (*it)) break;
    it++;
  }
  return it != searchlist.end() ? &(*it) : NULL;
};
Folgendes aber nicht:
Code:
template<typename T_ListElement>
  std::list<T_ListElement>::iterator // Rückgabewert: iterator auf das Listenelement
  FindInList
  (const std::list<T_ListElement> &searchlist,
  const T_ListElement &Element)
{
  std::list<T_ListElement>::iterator it = searchlist.begin();
       
  while(it != searchlist.end())
  {
    if(Element == (*it)) break;
    it++;
  }
  return it;
};
Hier sind die (ersten) Fehlermeldungen:
c:\Projekte\...\globals.h(66) : warning C4346: 'std::list<_Ty>::iterator': Abhängiger Name ist kein Typ
Präfix mit 'typename' zum Angeben eines Typs
c:\Projekte\...\globals.h(66) : error C2146: Syntaxfehler: Fehlendes ';' vor Bezeichner 'FindList'
c:\Projekte\...\globals.h(66) : error C2501: 'std::list<_Ty>::iterator': Fehlende Speicherklasse oder Typspezifizierer
c:\Projekte\...\globals.h(66) : error C2065: 'T_ListElement': nichtdeklarierter Bezeichner
c:\Projekte\...\globals.h(66) : error C2955: 'std::list': für die Verwendung einer Vorlagenklasse ist eine Vorlagen-Argumentliste erforderlich
c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\list(966): Siehe Deklaration von 'std::list'
c:\Projekte\...\globals.h(66) : error C2955: 'std::list': für die Verwendung einer Vorlagenklasse ist eine Vorlagen-Argumentliste erforderlich
c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\list(966): Siehe Deklaration von 'std::list'
c:\Projekte\...\globals.h(67) : error C2143: Syntaxfehler: Es fehlt ',' vor '&'
Die Fehlermeldungen beziehen sich alle auf den Funktionskopf. Wie man sehen kann, arbeite ich mit VC.NET 2003.
Ich würde lieber einen iterator (oder sogar const_iterator) als einen Zeiger zurückgeben.

Kann mir jemand den Grund für die Fehlermeldungen nennen und wie ich es schaffen kann einen std::list<...>::iterator aus der Templatefunktion zurückzugeben?
 
Ich bin mir nicht sicher, aber ich meine, bei solchen Problemen ist der Compiler zu dämlich, den Template-Parameter richtig abzuleiten. Du musst dann nochmal explizit den Typ (type oder class) angeben:

Code:
template<typename T_ListElement>
  std::list<typename T_ListElement>::iterator // Rückgabewert: iterator auf das Listenelement
  FindInList
  (const std::list<typename T_ListElement> &searchlist,
  const T_ListElement &Element)
{
  std::list<typename T_ListElement>::iterator it = searchlist.begin();
       
  while(it != searchlist.end())
  {
    if(Element == (*it)) break;
    it++;
  }
  return it;
};

Ich kann aber auch ganz gut vollkommen daneben liegen :D
 
Also bei mir funktioniert es, wenn ich ein "const" entferne. Und ich habe "class" statt "typename" verwendet:
Code:
template<class T_ListElement>
  std::list<T_ListElement>::iterator // Rückgabewert: iterator auf das Listenelement
  FindInList
  (std::list<T_ListElement> &searchlist,
  const T_ListElement &Element)
{
  std::list<T_ListElement>::iterator it = searchlist.begin();
       
  while(it != searchlist.end())
  {
    if(Element == (*it)) break;
    it++;
  }
  return it;
};
 
Hi.
Code:
template<typename T_ListElement>
  std::list<T_ListElement>::iterator // Rückgabewert: iterator auf das Listenelement
  FindInList
  (const std::list<T_ListElement> &searchlist,
  const T_ListElement &Element)
{
  std::list<T_ListElement>::iterator it = searchlist.begin();
       
  while(it != searchlist.end())
  {
    if(Element == (*it)) break;
    it++;
  }
  return it;
};

Ich bin mir nicht sicher, aber ich meine, bei solchen Problemen ist der Compiler zu dämlich, den Template-Parameter richtig abzuleiten. Du musst dann nochmal explizit den Typ (type oder class) angeben:
Ja. Im Grund richtig. Wie sollte denn der Compiler an dieser Stelle auch wissen, dass std::list<T_ListElement>::iterator der Name eines Typs ist? Das kann er nicht wissen bevor das Template nicht instanziert wird, was erst passiert wenn man die Funktion aufruft.

Du mußt aber nicht angeben das T_ListElement ein Typ ist - das ist schon klar.

Also bei mir funktioniert es, wenn ich ein "const" entferne. Und ich habe "class" statt "typename" verwendet:
Erstmal ist es völlig egal ob man innerhalb der template Paramterliste typename oder class verwendet.

Dann ist es eigentlich richtig den const Typspezifizierer für den Parameter zu verwenden, denn die Funktion verändert die Liste ja nicht / bzw. darf die Liste nicht ändern. Dann kann man allerdings nicht mit einem "normalen" Iterator darauf zugreifen, sondern nur mit einem const_iterator.

C++:
template<typename T_ListElement>
  typename std::list<T_ListElement>::const_iterator // Rückgabewert: iterator auf das Listenelement
  FindInList
  (const std::list<T_ListElement> &searchlist,
  const T_ListElement &Element)
{
  typename std::list<T_ListElement>::const_iterator it = searchlist.begin();
       
  while(it != searchlist.end())
  {
    if(Element == (*it)) break;
    it++;
  }
  return it;
};

@jokey2: Warum verwendest du denn nicht den find Algorithmus aus der Standardbibliothek? Wenn du den nachprogrammieren wolltest, hättest du ja auch in den Headerdateien nachschauen können.

Gruß
 
Erstmal Danke füe die hilfreichen Antworten und sorry, daß es etwas länger gedauert hat, bis ich mich wieder melde, da ich krank war.
Warum verwendest du denn nicht den find Algorithmus aus der Standardbibliothek? Wenn du den nachprogrammieren wolltest, hättest du ja auch in den Headerdateien nachschauen können.
Was verwenden, was schon da ist, das kann ja jeder :-) Ernst beiseite, es ging mir hauptsächlich um das tiefere Verständnis von Template-Funktionen.
So hat die Funktion jetzt das gewünschte Ergebnis und läßt sich kompilieren:
Code:
template<typename T_ListElement> 
    typename std::list<T_ListElement>::iterator
    FindList
    (std::list<T_ListElement> &searchlist, 
    const T_ListElement &Element)
{
    typename std::list<T_ListElement>::iterator it = searchlist.begin();

    while(it != searchlist.end())
    {
        if(Element == (*it)) break;
        it++;
    }
    return it;
};
Da ich keinen const_iterator zurückgeben wollte, habe ich das const vor der Liste weggelassen.
Es lag also am 'typename' vor 'std::list<T_ListElement>::iterator'. Ich hatte es so probiert:
Code:
std::list<typename T_ListElement>::iterator
aber das hatte nicht geklappt.

P.S.: Gibt es eine Möglichkeit, einen const_iterator in einen iterator umzuwandeln? Hab nichts gefunden.
 
Da ich keinen const_iterator zurückgeben wollte, habe ich das const vor der Liste weggelassen.
Es lag also am 'typename' vor 'std::list<T_ListElement>::iterator'. Ich hatte es so probiert:
Code:
std::list<typename T_ListElement>::iterator
aber das hatte nicht geklappt.

P.S.: Gibt es eine Möglichkeit, einen const_iterator in einen iterator umzuwandeln? Hab nichts gefunden.
Nein, das ist generell nicht möglich. Wenn du den Wert in der Liste noch ändern willst mußt du einen non-const iterator zurückgeben. Da ist halt leider das Design deiner Funktion ein bißchen unglücklich: es funktioniert erstmal nur für Listen, nur für komplette Listen und dann eben entweder nur für nicht-konstante Listen oder für konstante und nicht-konstante Listen, wo du aber dann den Wert nicht ändern kannst.

Der find Algorithmus wie er in der STL definiert ist, hat diese Einschränkungen nicht.

Gruß
 
Zurück