Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Problem mit Templates

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
11.12.2007, 12:32 Uhr
~Hutchinson
Gast


Hallo,

nach einigen Jahren, versuche ich mich wieder in C++ reinzudenken. Leider bin ich bei meinen Versuchen mit Templates ein wenig ratlos.

Ich versuche einen Template-Ausgabeoperator in eine .cpp-Datei auszulagern. Das funktioniert aber leider nicht.
Solange der Operator in der Header-Datei definiert ist (siehe unten), funktioniert das Programm so, wie es soll. Steht allerdings die Deklaration in der Header-Datei und die Implementierung in der .cpp-Datei, bekomme ich abwechselnd und offenbar relativ zufällig verschiedene Compiler oder Linker-Fehler. Die sinnvollste war dabei noch "Undefined Symbol operator<<...".

Wäre schön, wenn mir jemand von euch auf die Sprünge helfen könnte... Bin offenbar im Moment zu vernagelt um eine Lösung zu finden.

Vielen Dank,

Hutchinson

---

Der Code sieht folgendermaßen aus:

main.cpp:

C++:
#include <iostream>
#include "test.h"
using namespace std;

int main (int argc, char * const argv[]) {
    // insert code here...
    Test<int> t;
    t.setX(10);
    cout << t;
    return 0;
}



test.h

C++:
#ifndef testClassHeader
#define testClassHeader

#include <iostream>

using namespace std;

template <typename T>
class Test {
private:
    T x;
public:
    Test() {x = 0;}
    
    void setX(T val) { x = val; }
    T getX() const { return x; }
    
};

template <typename S>
ostream& operator<< (ostream &os, const Test<S> & t);

template <typename S>
ostream & operator<< (ostream & os, const Test<S> & t) {
    os << t.getX();
    return os;
}
#endif



test.cpp:

C++:

#include "test.h"
/*template <typename S>
ostream & operator<< (ostream & os, const Test<S> & t) {
    os << t.getX();
    return os;
}*/


 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
11.12.2007, 13:08 Uhr
xXx
Devil


hmm

C++:
#if !defined(PRINT_HPP_INCLUDED)
#define PRINT_HPP_INCLUDED

#if (_MSC_VER >= 1300)
#pragma once
#endif // (_MSC_VER >= 1300)

#include <iostream>

template <typename _Type>
class print
{
    _Type m_data;

public:
    print(_Type const& data)
        : m_data(data)
    {}
    
public:
    void set_data(_Type const& data) { m_data = data; }
    _Type const& get_data() const { return m_data; }
    
public:
    friend std::ostream& operator<<(std::ostream& out, print<_Type> const& data)
    { return (out << data.m_data); }
};

#endif // PRINT_HPP_INCLUDED


C++:
#include <iostream>
#include "test.h"

int main ()
{
    std::cout << print<int>(-10) << std::endl;
}


Aja noch nebenbei ... niemals using namespace std im Header und bitte nicht irgendwelche Funktionsköpfe für main selbst ausdenken ... das const hat da nix zu suchen!
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
11.12.2007, 13:44 Uhr
ao

(Operator)


Die Regel "Funktionsköpfe in den Header, Implemetierungen in eine eigene Übersetzungseinheit" gilt nicht für Templates.

Templates sind in diesem Punkt "wie Präprozessor-Makros". Sie müssen im Header ausprogrammiert werden, weil der Compiler zur Übersetzungszeit den vollständigen Code braucht und nicht nur die Aufruf-Signatur.

ao
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
11.12.2007, 13:47 Uhr
~Hutchinson
Gast


Erstmal danke für die Antwort. Leider habe ich mein Anliegen wohl etwas ungenau formuliert. Mein Ziel ist es den Operator in der .cpp-Datei zu implementieren, nicht im Header. Das gelingt mir leider auch mit deinem Beispiel nicht. Offenbar fehlt mir da an einer entscheidenden Stelle das Verständnis.
Mit Memberfunktionen und den Operatoren in einer Klasse ohne Template ist das kein Problem. Auch Memberfunktionen innerhalb eines Klassentemplates klappt das (Deklaration im Header, Implementierung im Source-File).


Zitat von xXx:
Aja noch nebenbei ... niemals using namespace std im Header und bitte nicht irgendwelche Funktionsköpfe für main selbst ausdenken ... das const hat da nix zu suchen!


Okay, das mit namespace sehe ich ein. Der Funktionskopf stammt von XCode (MacOS X), der legt das so an, war mir nicht aufgefallen.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
11.12.2007, 13:59 Uhr
~Hutchinson
Gast



Zitat von ao:
Die Regel "Funktionsköpfe in den Header, Implemetierungen in eine eigene Übersetzungseinheit" gilt nicht für Templates.


Danke ao, das erklärt alles und ist auch eigentlich das, was ich erwartet habe. Leider sind Templates absolutes Neuland für mich. Als ich vor 4-5 Jahren mit C++ gearbeitet habe, habe ich sie aufgrund der damaligen Unterstützung durch die Compiler gemieden...

Das Auslagern von Memberfunktionen (z.B. ein Operator += als Memberfunktion mit Test<T> & t als Parameter) funktioniert tadellos. Das fand ich etwas überraschend.

Jedenfalls vielen Dank für die Antwort.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
11.12.2007, 16:08 Uhr
0xdeadbeef
Gott
(Operator)


Das Auslagern der Implementierung ist nicht nur möglich, sondern häufig auch guter Stil. Allerdings - der Punkt hier ist, dass Klassenvorlagen halt keine Klassen sind, die vom Compiler zu Klassen konkretisiert werden. Damit der Compiler das aber konkretisieren kann, muss er den ganzen Code kennen.

Die GNU-Leute helfen sich gerne, indem sie die Deklaration in einem Header und die Definition in eine gleichnamige .tcc-Datei schreiben, um dann am Ende des Headers

C++:
#include "foo.tcc"


zu schreiben. Ob das guter Stil ist, darüber kann man sich lange streiten. Prinzipiell gibt es im Standard auch das Schlüsselwort "export," was etwas in der Art machen soll, allerdings gibt es, soweit ich weiß, nur einen Compiler, der das implementiert (Comeau), und alle anderen fragen sich noch, wie zum Teufel die das gemacht haben.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
11.12.2007, 21:04 Uhr
~Hutchinson
Gast


Interessante Information 0xdeadbeef, danke dafür.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: