Templates kai C++
Vasilis Vasaitis
vvas at hal.csd.auth.gr
Wed Jul 23 00:11:03 EEST 2003
On Tue, Jul 22, 2003 at 08:35:25PM +0300, Dimitris Tasoulis wrote:
>
> Geia xara, exo na kano mia periergi erotisi sxetika me tis template
> claseis tis C++.
>
> Exo ftia3ei mia template class (List.h) gia double linked list.
> Prospa8o tora na kano compile to antistixo List.cpp kai ta kataferno mia
> xara. Kanontas omos include to List.h sto main kai dinontas
> sto g++ to List.o gia na kanei to linking den ta katafernei.
>
> To error pou vgazei einai to e3is:
> /tmp/ccxRfwoG.o: In function `main':
> /tmp/ccxRfwoG.o(.text+0x22): undefined reference to `List<int>::add(int)'
> collect2: ld returned 1 exit status
>
> Mipos mporei na voi8eisei kapoios?
Λοιπόν, δικαιολογημένη η απορία σου στη συγκεκριμένη περίπτωση, αλλά
πρόσεξε τι συμβαίνει:
- Όταν μεταγλωττίζεται το List.cpp, ο g++ δε βλέπει την ανάγκη να
παράγει καμία εκδοχή του template για συγκεκριμένο τύπο, και επομένως
δεν το κάνει.
- Όταν μεταγλωττίζεται το main_bad.cpp, ο g++ δε βλέπει μπροστά του
κάποιον ορισμό της List<int>::add(int), οπότε αναγκαστικά υποθέτει ότι
είναι εξωτερικό σύμβολο που θα βρεθεί κατά τη σύνδεση.
- Όταν γίνεται η σύνδεση, ο ld δεν έχει ιδέα πού θα μπορούσε να βρει
τη ζητούμενη συνάρτηση, αφού δεν υπάρχει σε κανένα από τα object files
που δέχεται ως είσοδο, οπότε εγκαταλείπει την προσπάθεια.
Ουσιαστικά, αυτό που θα ήθελες εσύ (υποσυνείδητα τουλάχιστον) είναι
ο linker, όποτε δε βρίσκει ένα σύμβολο που προέρχεται από κάποιο
template, να καλεί τον compiler, ο οποίος να παράγει το σχετικό
template instantiation ανάλογα με την περίπτωση. Δυστυχώς ή ευτυχώς,
στον κόσμο του Unix, με την όλη φιλοσοφία των ξεχωριστών εργαλείων, δε
δουλεύουν έτσι τα πράγματα.
Από εκεί και πέρα, υπάρχουν δυο τρόποι που μπορείς να λύσεις το
πρόβλημά σου:
- Να συμπεριλαμβάνεις όλους τους ορισμούς και την υλοποίηση του
template στο αρχείο .h, όπως κάνει όλος ο κόσμος. Το πλεονέκτημα της
λύσης αυτής είναι ότι ξαφνικά όλα δουλεύουν αυτόματα και χωρίς να
χρειάζεται να κάνεις τίποτα άλλο. Το μειονέκτημα είναι ότι καταλήγει ο
compiler να παράγει τα template instantiations για κάθε αρχείο πηγαίου
κώδικα που χρησιμοποιεί το template (δηλαδή παραπάνω χρόνος
μεταγλώττισης), και ότι σε «χαζά» περιβάλλοντα ανάπτυξης προγραμμάτων
(το GNU περιβάλλον *δεν* είναι ένα από αυτά) όλα αυτά τα
instantiations καταλήγουν σε πολλαπλά αντίτυπα στο τελικό εκτελέσιμο.
Αν δε με πιστεύεις ως προς το περί «όλου του κόσμου», απλά ρίξε μια
ματιά στα αρχεία επικεφαλίδας της βιβλιοθήκης του g++, όπου απλά
περιλαμβάνονται όλα τα template της πρότυπης βιβλιοθήκης.
- Να παράγεις χειροκίνητα όλα τα instantiations που πρόκειται να
χρησιμοποιήσεις. Π.χ., στη συγκεκριμένη περίπτωση, αρκεί να προσθέσεις
στο List.cpp ένα:
template List<int>;
Τα πλεονεκτήματα και μειονεκτήματα αυτής της λύσης είναι, χωρίς
καμία έκπληξη, τα ακριβώς αντίστροφα με αυτά της παραπάνω (την οποία
και προτείνω).
Αν έχοντας διαβάσει όλα τα παραπάνω, αυτά δε σου φαίνονται τόσο
προφανή όσο μου φαίνονται εμένα, ζήτα επιπλέον διευκρινήσεις. ;^)
--
Vasilis Vasaitis
vvas at hal.csd.auth.gr
+306976604701
More information about the Linux-greek-users
mailing list