14. april 2003 - 14:55Der er
9 kommentarer og 1 løsning
Templates problem / "Unresolved external symbol"
Jeg sidder og er i gang med at lave en kø-klasse, som via templates gerne skulle understøtte forskellige datatyper. Jeg kan udmærket compile klassen, men når jeg forsøger at anvende den i et testprogram får jeg fejlen "Unresolved external symbol:", hver gang der laves et kald til klassen. Nu er jeg ikke så meget inde i templates, og jeg kan ikke se, hvad der er galt. Herunder er headeren til klassen:
template< class T > class RingFIFO { // Overload af stream insertion operator. friend ostream &operator<< (ostream &out, const RingFIFO &ob) ; public: RingFIFO(int size = 10) ; RingFIFO(const RingFIFO &ob); // Copy constructor ~RingFIFO() ; RingFIFO &operator=(const RingFIFO &ob) ; bool putData(T value) ; T getData() ; bool isFull() ; bool isEmpty(); int count() ; private: int size ; T *data; int front ; int back ; };
Herunder nøjes jeg med at indsætte koden til constructor og destructor for ikke at gøre spørgsmålet for langt: #include "RingFIFO.h"
// Constructor template<class T> RingFIFO<T>::RingFIFO(int qSize) { size = qSize ; data = new T [size] ; for ( int i = 0 ; i < size ; i++ ) *(data+i) = 0 ; front = 0 ; back = 0 ; }
Endelig forsøger jeg at benytte klassen i et test program. Her går det galt: #include "RingFIFO.h" int main() { RingFIFO<int> iQ ; RingFIFO<double> dQ(2) ; return 0 ; }
Det virker når det ligger i en fil. Nu vil jeg meget gerne have forklaret, hvorfor ? Og er der ikke en måde at undgå, at det hele kommer til at ligge i en fil ?
Forklaringen er, at din objektkode ikke kan instantieres før oversætteren ved hvilken template parameter du bruger (altså, om du har gang i en RingFIFO<int>, en RingFIFO<double>, eller en RingFIFO<SvendBent>, hvor SvendBent er en af dine egne klasser). Så definitionen af RingFIFO i .h filen er ikke nok til at lave objektkoden til RingFIFO<int> eller nogen af de andre, .cc filen skal med.
Pointen er, at du kan bruge hvad som helst som template-parameter. Og oversætteren generer en gang objektkode til RingFIFO<int>, en ny gang objektkode til RingFIFO<double> og så videre. Det betyder også at du ved brug af templates risikerer en eksplosion i størrelsen af din objektkode. Der er et par fif man kan bruge i den forbindelse.
Det mest klassiske fif er partiel specialisering for pointere. Du laver en fuld specialisering for void*, og så laver du en partiel specialisering til T*, som bruger void* specialiseringen, men cast'er pænt.
Arne> Ja, du skal have både definition (normalt i .h filen) og erklæring (normalt i .cc filen) ind hvor du skal instantiere. Normalt er det nok med .h filen, men med templates skal erklæringen også med (indtil oversætter teknologien bliver smart nok til at understøtte import keyword'et fra ANSI C++).
Hvis du (som jeg) foretrækker stadig at have definition og erklæring hver for sig, så kan du lade din .h fil slutte med #include "filnavn.cc".
olennert> Det er ganske rigtigt en god måde at få meget store exe filer på medmindre at jeg fejlagtigt erindre at Bjarne har lovet mig at der kun skulle komme en function for hver template instatirering, så selvom du tager det hele med i hver objectfil skulle det endelige program eliminere duplikerede instatierede functioner.
Skulle dette ikke være tilfældet (som i min ikke helt standard compiler) kan man snyde lidt og gøre compilerens arbejde for den, bruge .h i alle object filer og lave en særlig instance fil, hvor du instantierer alle de templates du bruger i programmet og for dermed oprettet alle de nødvendige functioner og hermed fjernet linker fejlen.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.