Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

kiba

Alter Hase

  • »kiba« ist der Autor dieses Themas

Beiträge: 327

Wohnort: NRW

Beruf: Azubi: Fach-Info. Anw.

  • Private Nachricht senden

1

28.05.2012, 23:32

Templates über mehere Dateien und Multi. Def.

Hi, Leut hab ein komisch Feher den ich nich so verstehe.
Unter Linux comp. er mein Programm doch unter Windows hat der da so paar Probleme.

Hab in einer .hpp-Datei eine template-Function definert und in einer weiteren .cpp-Datei dann die Spezi zu den Templates.
Dann hab ich noch eine Klasse und für diese Klasse gibt es noch eine Spezi Template in der Klassen .cpp-Datei.
das sieht dann Ungefähr so aus:

basis.hpp

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace FileBinary{

template<class T>
std::ostream& writeBinary(std::ostream& stream,const T& value){ ///< first defined here
    stream.write(reinterpret_cast<const char*>(&value),sizeof(value));
    return stream;
}

template<class T>
std::istream& readBinary(std::istream& stream,T& value){
    stream.read(reinterpret_cast<char*>(&value),sizeof(value));
    return stream;
}
}


basis.cpp

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
namespace FileBinary{

template<>
std::ostream& writeBinary<std::string>(std::ostream& stream,const std::string& str){
    uint32_t strlength = str.length();
    stream.write(reinterpret_cast<const char*>(&strlength),sizeof(strlength));
    stream.write(str.c_str(),strlength);
    return stream;
}

template<>
std::istream& readBinary<std::string>(std::istream& stream,std::string& str){
    uint32_t strlength = 0;
    stream.read(reinterpret_cast<char*>(&strlength),sizeof(strlength));

    char* buffer = new char[strlength+1]();

    stream.read(buffer,strlength);
    str = buffer;

    delete[] buffer;
    return stream;
}

}


Foo.hpp

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
#include "basis.hpp"

class Foo{
   private:
   int id;
   std::string name;
   std::string filename;
   // ...
};


Foo.cpp

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace FileBinary{
    template<>
    std::ostream& writeBinary<Foo>(std::ostream& stream,const Foo& obj){ ///< multiple definition of `std::ostream& FileBinary::writeBinary<Foo>(std::ostream&, Foo const&)'
        writeBinary(stream,obj.id);
        writeBinary(stream,obj.name);
        writeBinary(stream,obj.filename);
        // ...
        return stream;
    }

    template<>
    std::istream& readBinary<Foo>(std::istream& stream,Foo& obj){
        readBinary(stream,obj.id);
        readBinary(stream,obj.name);
        readBinary(stream,obj.filename);
        // ...
        return stream;
    }

}



Fehler:
multiple definition of `std::ostream& FileBinary::writeBinary<Foo>(std::ostream&, Foo const&)'
first defined here

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

2

28.05.2012, 23:51

Mach die Funktionen inline.
Rufst du das template für Foo in einer anderen Datei als Foo.cpp auf?
Wieso brauchst du eine Spezialisierung des template, reicht Overloading nicht aus?

kiba

Alter Hase

  • »kiba« ist der Autor dieses Themas

Beiträge: 327

Wohnort: NRW

Beruf: Azubi: Fach-Info. Anw.

  • Private Nachricht senden

3

29.05.2012, 00:06

Ja templates für die Foo klasse wirden dann noch in anderen Klassen aufgerufen.
Wollt das Template machen damit ich die Standard Datentypen nicht alle überladen muss.

Hab die template in der .hpp datei inline gemacht, funkt aber nicht.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

4

29.05.2012, 00:50

Das Problem ist wohl, dass das template damit zweimal auf verschiedene Weise instanziert wird. In Foo.cpp wird die Spezialisierung instanziert, in der anderen Datei ist die Spezialisierung nicht bekannt, daher wird das normale template für Foo instanziert. Die Lösung: Template explizit instanzieren: Im Header per extern template und dann in Foo.cpp definieren.

Wie gesagt, zuallererst würd ich mir aber überlegen ob du hier überhaupt spezialisieren willst oder vielleicht nicht doch einfach nur überladen...

Wollt das Template machen damit ich die Standard Datentypen nicht alle überladen muss.

Du kannst das template haben und zusätzlich normale Funktionen mit dem gleichem Namen und Overloading kümmert sich um alles ;)
Das template ist nur eine Vorlage mit der Funktionen bei Bedarf produziert werden können.
Guter Artikel darüber: http://www.gotw.ca/publications/mill17.htm

Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von »dot« (29.05.2012, 01:14)


dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

5

29.05.2012, 01:04

Mit extern template würde das dann so aussehen:

basis.hpp

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace FileBinary{

  template <class T>
  std::ostream& writeBinary(std::ostream& stream, const T& value){
    // template Definition
  }

  // Spezialisierung deklarieren
  template <>
  std::istream& readBinary<Foo>(std::istream& stream, Foo& value);

  // explizite Instanzierung deklarieren, sagt dem Compiler dass readBinary<Foo> bereits wo anders instanziert wurde
  extern template std::istream& readBinary<Foo>(std::istream& stream, Foo& value);
}


Foo.cpp

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
namespace FileBinary{

  template<>
  std::ostream& writeBinary<Foo>(std::ostream& stream,const Foo& obj){
    // Definition der Spezialisierung
  }

  // Spezialisierung explizit instanzieren
  template std::istream& readBinary<Foo>(std::istream& stream, Foo& value);
}

kiba

Alter Hase

  • »kiba« ist der Autor dieses Themas

Beiträge: 327

Wohnort: NRW

Beruf: Azubi: Fach-Info. Anw.

  • Private Nachricht senden

6

29.05.2012, 10:07

thx für das Beispiel wusste garnich was ich da alles definieren, deklar. oder expli. sollte.

Das mit den überladen funktioniert aber auch nur wenn die parameter sich ändern bei ein andere Rückgabewert Funkioniert was dann nicht mehr.

C-/C++-Quelltext

1
2
3
4
5
6
7
template<class T>
T& getBar(std::string str);

// das würde dann ja nicht gehen

int getBar(std::string str);
double getBar(std::string str);

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

7

29.05.2012, 13:49

Ja natürlich, in deinem Fall hast du aber eben auch andere Parameter ;)

Werbeanzeige