🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: de.comp.lang.c++
4 messages
4 total messages Started by root Sun, 03 Mar 1996 08:19
most-faq: template instantiation&compiler specifics
#1728
Author: root
Date: Sun, 03 Mar 1996 08:19
95 lines
5333 bytes
Wenn mich nicht alles taeuscht, ist die Frage nach dem richtigen Umgang mit
template-member-Funktionen (tmf) die am haeufigsten gestellte und nie richtig
beantwortete Frage. 
Daher hier, nach Lektuere von 
- g++-info:templates,
- SUN C++ 4.0.1 user manual,
- FAQ for g++ and libg++,
- threads in comp.lang.c++(.moderated), comp.std.c++, de.comp.lang.c++,
  gnu.lang.help mit subject "... template ...",
meine Version der Frage.

Ursache des Problems ist wohl, dass manche c++-Fans (leider auch die meisten 
Compilerhersteller) meinen, der Compiler muesste so schlau sein, nur die tmf 
Instanzen zu erzeugen, die tatsaechlich verwendet werden. Dazu gibt es laut 
g++-info (bestaetigt durch ein posting eines *borland.com und SUNs C++ 
4.0.1-Handbuch) zwei Ansaetze:
1. Borland-C++:
   Template-Deklaration und -Definition in die header-Datei schreiben, ein
   spezieller Linker filtert die entstandenen Redundanzen heraus.
   Nachteil:
	Damit kann man das Konzept:
	- header-Datei = Schnittstellendeklaration,
	- Programm-Datei = Programmimplementation,
	endgueltig vergessen. Und damit auch die Wartung groesserer Projekte.
2. Cfront (AT&T, mit Einschraenkungen SUN C++):
   Irgendwoher "weiss" der Compiler, wo die tmf definiert sind, bestimmt,
   welche Instanzen notwendig sind und erzeugt diese.
   Leider fehlt bei den meisten Rechnern die Einfuelloeffnung fuer Maggi.
   SUN behilft sich mit TemplateDB-Verzeichnissen. Das scheint aber, wenn 
   ueberhaupt, nur zu funktionieren, wenn
   - header und source den gleichen Basisnamen haben und
   - alle Quellen im gleichen Verzeichnis stehen.
   g++ bietet in der Standardversion eine aehnliche Moeglichkeit durch die
   Verwendung von "#pragma interface <FILE>"/"#pragma implementation", mit
   der Compiler-Optionen "-fexternal-templates" und dem Eintrag 
   "template class <Instanzen-Bezeichnung>;" in der tmf-Definitionsdatei.
   Nachteil:
	Es entsteht ein zusaetzlicher Verwaltungsaufwand, mit dem sich der
	Programmentwickler sehr bald selbst beschaeftigen muss. Bei grossen
	Projekten wird ein erheblicher Teil der Dateistruktur in die 
	Programmquellen einfliessen. Dann ist es mit der Modularitaet und
	Wiederverwendbarkeit ebenfalls vorbei.
Gemeinsammer Nachteil der beiden Methoden:
	sie sind miteinander unvertraeglich.
Ergebnis:
   Der Ansatz "der Compiler/Linker erzeugt aus templates genau die benoetigten
   Instanzen" ist ebenso schoen wie falsch:
   Hoffen: ja, natuerlich; Wissen: nein, leider; Tun: _NEIN_! niemals!

Bleibt als 3. Moeglichkeit die triviale Loesung der "expliziten 
Instanzenbildung"
Ansatz:
   - Templates sind Werkzeuge, mit denen man durch einmaliges Codieren mehrere
     aehnliche Klassen/Funktionen erzeugt.
   - Aus einer Quelldatei erzeugte Objektdateien enthalten den Code, der
     auf Grund des Inhaltes der Quelldatei, dort eingeschlossener header-
     Dateien, sowie der Compiler-Optionen erzeugt wurde.
   - Beim Uebersetzen der tmf muss der Compiler wissen, welche Instanzen 
     erzeugt werden sollen.
   - Beim Uebersetzen der Anwendungsprogramme sollte der Compiler wissen,
     welche Instanzen zur Verfuegung stehen, d.h. wann er eine Fehlermeldung
     ausgeben muss.

Vorteil:
   - Selbst MS-Programmierer muessten in der Lage sein, das zu implementieren.
   - Waere dies die allgemein empfohlene, standardmaessig implementierte Art,
     wuerde die Zahl der postings vom Typ "HELP: LINKER ERROR: UNDEFINED"
     drastisch reduziert.
   - Der Uebergang zwischen "eigenen" templates und templates fuer/in
     libraries ist zwanglos moeglich.
   - Die aus C uebernommenen Ansaetze, die Modularisierung in die
     Dateistruktur abzubilden, bleiben erhalten.

Realisierung:
1. g++:
   Mit Eintrag "template class <Instanzen-Bezeichnung>;" fuer jede gewuenschte
   Instanz in der Datei mit den Definitionen der tmf erzwingt man die 
   Erzeugung der entsprechenden Memberfunktionen. Die Compiler-Option
   "-fno-implicit-templates" sorgt dafuer, dass diese global verwendet werden.
   Nachteil (soweit ich es bisher ausprobiert habe):
	- Bei Verwendung von "-fno-implicit-templates" werden auch inline
	  template-Funktionen nicht mehr automatisch expandiert.
	- Schade, aber nicht wirklich stoerend: "template class ..." muss in
	  der Quelle, nicht im header stehen (sonst gibt's "multiple 
	  defined"). So merkt erst der Linker, wenn eine Instanz fehlt.
2. SUN C++ 4.0.1:
   Mit dem Eintrag "template class ..." kann er nichts anfangen. Bisher weiss
   ich nichts Besseres als in der Definitionsdatei der tmf dummy-Programme
   anzuhaengen, die jede Memberfunktion einmal afurufen. Das kann ja wohl
   nicht wahr sein!
   Zusaetzlich scheint man dem Compiler die Option "-pto" geben zu muessen,
   damit die tmf-Instanzen global werden. Fuer die Bildung der Modul-
   libraries scheint man "CC -xar" (statt "ar") verwenden zu muessen.

MfG, Gerhard.
Re: most-faq: template instantiation&compiler specifics
#1735
Author: Jan Willamowius
Date: Sun, 03 Mar 1996 15:18
40 lines
1954 bytes
root@gt-priv.m.eunet.de (root) writes:
>2. Cfront (AT&T, mit Einschraenkungen SUN C++):
>[...]
>   SUN behilft sich mit TemplateDB-Verzeichnissen. Das scheint aber, wenn 
>   ueberhaupt, nur zu funktionieren, wenn
>   - header und source den gleichen Basisnamen haben und
>   - alle Quellen im gleichen Verzeichnis stehen.

Ich portiere gerade von Watcom nach cfront und kann ein paar Details
beitragen:

Das Verzeichnis ist kein Problem. Es wird ueberall auf dem Includepfad
gesucht.

Watcom ist auch durchaus in der Lage die Implementationen zu finden, auch
wenn sie nicht den gleichen Basisnamen haben bzw. ueber mehrere
Dateien verstreut sind. (Ob man ihm noch auf die Spruenge helfen muss
entzieht sich meiner Kenntnis).

Cfront kann man mit sog. Map-Dateien in seinen Repository ebenfalls
auf die Spruenge helfen wo er die Implementationen finden soll. (Ugly!)

Wer neuen Code schreibt tut sich sicherlich einen Gefallen, wenn die
Dateinamen gleich sind. Man weiss ja nie mit welchem kranken Compiler er
mal uebersetzt werden wird.

Die Geschwindigkeit in der cfront die Templates instanziiert ist
unglaublich und verschafft regelmaessig Gelegenheit zu einem laengeren
Kloenschnack.

Es gab hier doch mal eine Diskussion, dass sich der g++ je nach
Plattform bzw. Linker (z.B. Linux vs. FreeBSD) auch unterschiedlich
verhaelt. Kann jemand das nochmal erklaeren ?

Gruss,
	Jan
-- 
Jan Willamowius, Semperstr. 1, 22303 Hamburg, Germany
Tel. 040 / 280 62 09, E-Mail: jan@janhh.shnet.org
WWW: "http://swt1.informatik.uni-hamburg.de/~1willamo/"
Re: most-faq: template instantiation&compiler specifics
#1733
Author: Dietmar Kuehl
Date: Sun, 03 Mar 1996 21:27
98 lines
5647 bytes
Hi,
root (root@gt-priv.m.eunet.de) wrote:
: Wenn mich nicht alles taeuscht, ist die Frage nach dem richtigen Umgang mit
: template-member-Funktionen (tmf) die am haeufigsten gestellte und nie richtig
: beantwortete Frage. 

Ich kann nicht nachvollziehen, dass dies die am haeufigsten gestellte
Frage ist.  Obwohl die Frage in clc++m gelegentlich auftaucht, ist es
nicht so dass es uebermaessig viel gefragt wird. Derzeit erscheint mir
z.B. eher die Frage nach "renew" (in allen Variationen) deutlich
haeufiger zu sein...

: Ursache des Problems ist wohl, dass manche c++-Fans (leider auch die meisten 
: Compilerhersteller) meinen, der Compiler muesste so schlau sein, nur die tmf 
: Instanzen zu erzeugen, die tatsaechlich verwendet werden.

Das liegt vermutlich daran, dass eine Standard konforme C++
Implementation so schlau sein muss (OK, es gibt noch keine Standard,
aber diese Forderung wird mit ziemlicher Sicherheit im Standard
enthalten sein). Der Grund warum es derzeit keine Compiler gibt, der
Templates richtig behandelt liegt z.B. darin, dass die Definition von
Templates in ihrer jetztigen Form noch sehr jung ist. Aber ich bin mir
absolut sicher, dass sich die Compilerbauer den A**** aufreissen
werden, dem Standard zu genuegen und zwar so schnell wie irgend
moeglich! Der Markt fuer einen Standard konformen UND funktionsfaehigen
C++ Compiler ist gross. Sehr gross. Die Betonung liegt uebrigens
durchaus auf "funktionsfaehig" und gemeint ist nicht die Beschreibung,
in der der Compiler behauptet, was der Compiler kann!

: Dazu gibt es laut 
: g++-info (bestaetigt durch ein posting eines *borland.com und SUNs C++ 
: 4.0.1-Handbuch) zwei Ansaetze:
: 1. Borland-C++:
:    Template-Deklaration und -Definition in die header-Datei schreiben, ein
:    spezieller Linker filtert die entstandenen Redundanzen heraus.
:    Nachteil:
: 	Damit kann man das Konzept:
: 	- header-Datei = Schnittstellendeklaration,
: 	- Programm-Datei = Programmimplementation,
: 	endgueltig vergessen. Und damit auch die Wartung groesserer Projekte.

Zu fordern, dass es so gemacht wird, ist nicht Standard konform. Man
kann Deklaration und Definition von Templates trennen.

: 2. Cfront (AT&T, mit Einschraenkungen SUN C++):
:    Irgendwoher "weiss" der Compiler, wo die tmf definiert sind, bestimmt,
:    welche Instanzen notwendig sind und erzeugt diese.
:    Leider fehlt bei den meisten Rechnern die Einfuelloeffnung fuer Maggi.
:    SUN behilft sich mit TemplateDB-Verzeichnissen. Das scheint aber, wenn 
:    ueberhaupt, nur zu funktionieren, wenn
:    - header und source den gleichen Basisnamen haben und
:    - alle Quellen im gleichen Verzeichnis stehen.

Nein. Das ist nicht unbedingt noetig (zumindest nicht fuer den
generellen Ansatz; fuer die Implementation in SUN C++ schon...). Eine
Moeglichkeit, es so zu implementieren, dass man es auf beliebige Files
verteilen kann, besteht z.B. darin, aus den Files mit den Template
Source spezielle Objektfiles zu generieren, die Symbole enthalten, die
sagen, welche (Member-) Funktionen und Objekte definiert werden und wo
das entsprechende File steht. ggf. kann man auch eine Vorcompilierte
Fassung des entsprechenden Files Speichern.

: Bleibt als 3. Moeglichkeit die triviale Loesung der "expliziten 
: Instanzenbildung"

Es ist derzeit zwar womoeglich notwendig, dass es so gemacht wird, ist
aber keine "Loesung"!  Ein solcher Ansatz ist z.B. beim Arbeiten mit
STL irgendwo in der Groessenordnung von total unbrauchbar anzusetzen:
Ich verwende gelegentlich Klassen, deren Name, wenn ich alle Templates
ersetze (der Compiler ist bei Fehlermeldungen so freundlich, mir die
Arbeit abzunehmen :-), auf 1KB zugeht. ... und das sind noch nichtmal
"echte" Anwendungen! Niemand will sowas schreiben muessen. Ausserdem
ist das auch ein Maintainance-Problem: Aendere ich an der einen Stelle
einen Typ, aendern sich dutzende von anderen Typen.

:    - Waere dies die allgemein empfohlene, standardmaessig implementierte Art,
:      wuerde die Zahl der postings vom Typ "HELP: LINKER ERROR: UNDEFINED"
:      drastisch reduziert.

Ich empfehle, im Gegensatz zu dem Autor des urspruenglichen Artikels,
einen hypriden Ansatz, der sich z.B. mit g++ und SUN CC vertraegt: Man
schreibt Headerfiles fuer Templates wie die Headerfiles fuer andere
Klassen auch und included am Ende, abhaengig von einem Macro (z.B. fuer
SUN CC braucht man die Sourcen nicht zu includen), ggf.  die Datei, die
den selben Basisnamen wie das Headerfile hat, in der die entsprechenden
Template Funktionen/Objekte definiert werden. Das funktioniert
erstaunlich gut. Auch mit den derzeit verfuegbaren STL aehnlichen
Libraries. Einziger Haken: Die Executables werden teilweise elendig
gross.

:    - Die aus C uebernommenen Ansaetze, die Modularisierung in die
:      Dateistruktur abzubilden, bleiben erhalten.

Mit Standard konformen Compilern kommt das wieder...
--
dietmar.kuehl@uni-konstanz.de
http://www.informatik.uni-konstanz.de/~kuehl
I am a realistic optimist - that's why I appear to be slightly pessimistic
Re: most-faq: template instantiation&compiler specifics
#1748
Author: Ullrich von Bassewitz
Date: Mon, 04 Mar 1996 20:42
64 lines
3393 bytes
> 1. Borland-C++:
>    Template-Deklaration und -Definition in die header-Datei schreiben, ein
>    spezieller Linker filtert die entstandenen Redundanzen heraus.
>    Nachteil:
> 	Damit kann man das Konzept:
> 	- header-Datei = Schnittstellendeklaration,
> 	- Programm-Datei = Programmimplementation,
> 	endgueltig vergessen. Und damit auch die Wartung groesserer Projekte.

Das ist nicht so schlimm, s.u.
Dumm allerdings, wenn man Bibliotheken verkaufen will.

Weiterer Nachteil (zumindest theoretisch): Laengere Uebersetzungszeiten, da
bei jedem #include der ganze Code uebersetzt werden muss. Das laesst sich
durch precompiled Headers weitgehend abfangen. Fazit: In der einfachsten
Variante sehr einfach zu implementieren, wenn man precompiled Headers haben
will sehr aufwendig. Dafuer helfen precompiled Headers aber auch bei
"normalen" Includes.

> 2. Cfront (AT&T, mit Einschraenkungen SUN C++):

Die Frage ist, welchen Vorteil diese Loesung bietet. Mir fallen auf Anhieb
zwar einige kleinere, aber kein entscheidender Vorteil ein. Zudem ist die
Loesung aufwendig in der Implementation.

> Bleibt als 3. Moeglichkeit die triviale Loesung der "expliziten 
> Instanzenbildung"

Dieser Weg ist fuer kleine Programme gangbar. Fuer groessere Projekte mit
vielen Bibliotheken ist das praktisch nicht zu machen. Der Grund dafuer
liegt darin, dass man beim Verwenden einer Klasse immer genau wissen
muss, ob sich evtl. irgendwo in der Klassenhierarchie bis hinunter zur
Basisklasse irgendwo ein Template befindet. Oder ob irgendeine Klasse, die
man verwendet, vielleicht ein Objekt einer Template-Klasse oder einen
Abkoemmling davon als (evtl. private) Data-Member hat. Das Verfahren setzt
also eine Detail-Kenntnis der verwendeten Bibliotheken voraus, die weit
ueber das hinausgeht, was man zum normalen "nur Benutzen" der Bibliotheken
wissen muss.
Verschaerfend kommt natuerlich noch der umgekehrte Effekt: Die explizite
Instantiierung darf man nicht mehr als einmal machen, weil man sonst
"multiple defines" bekommt. Das ist enorm umstaendlich, wenn man zu mehrt an
einem Projekt arbeitet.

Ich behelfe mir bei den neueren Versionen von g++ mit dieser Methode - und
es ist jedesmal eine Kugelfuhr, herauszufinden, welches Template der
Compiler denn nun gerne instantiiert haette, und auch keines dabei mehrfach
zu erwischen.

Also ich denke, diese Moeglichkeit ist wesentlich schlechter fuer die
Wartbarkeit groesserer Projekte als die oben angefuehrte Methode, alles in
ein Header File zu packen. Natuerlich ist das auch keine besonders gute
Loesung, aber wenn meine Bibliothek einmal fertig ist, dann tut es immer.
Wenn ich explizite Instantiierung machen muss, dann habe ich - trotz
fertiger Bibliothek - andauernd ein Rumgemache in der Applikation.

Natuerlich nur meine Meinung...

Gruss


        Uz

-- 
Ullrich von Bassewitz                              uz@ibb.schwaben.com
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads