Templatefunktion für mehrere Module

Was passiert nun, wenn man sein Programm auf mehrere Quelltexte verteilt? In einem Modul steht die Definition der Templatefunktion, hier kann der Compiler beim Übersetzen alle nötigen Versionen erzeugen; er weiß aber nicht, welche benötigt werden. In den anderen Quelltexten steht nur eine Deklaration; der Compiler weiß hier, welche Versionen kompiliert werden müssen, sieht aber die dazu nötige Definition nicht und behandelt die benötigte Funktion deshalb als extern. Aus diesem Grund muß man in dem Modul mit der Definition alle benötigten Versionen explizit deklarieren (zum Beispiel im obigen Beispiel als int min( int, int ); usw.). Dann sieht der Compiler, was der Programmierer braucht und kann entsprechende Versionen in diesem Modul erzeugen. Dagegen ist es nicht immer empfehlenswert, die Definition über eine Headerdatei allen Modulen direkt zur Verfügung zu stellen: dann würden von ein und derselben Funktion eventuell mehrere Exemplare erstellt und zusammengebunden. Dies ist theoretisch nicht zulässig; auf manchen Systemen aber möglich. So wird das Programm nicht mehr portabel sein und außerdem unnötig groß.

Wie man es dreht und wendet, eine optimale Strategie für alle Fälle gibt es nicht. Man hat hier letztlich folgende Lösungsmöglichkeiten:

  1. Man erklärt die template-Funktion zu inline, und macht ihre Definition allen Modulen soweit nötig zugänglich, beispielsweise über eine Headerdatei.

  2. Man verzichtet auf inline (weil vielleicht die Funktion zu umfangreich ist), und macht trotzdem die Definition allen anderen Modulen zugänglich.

    Je nach System kann das zu langen Übersetzungszeiten und/oder großen Programmen führen. Daher ist diese Möglichkeit nicht generell empfehlenswert.

    Zudem kann man sich (ebenso wie bei der ersten Möglichkeit) Probleme einhandeln durch Definitionen vor dem jeweiligen #include, was zu unterschiedlichen Definitionen der Funktion in den verschiedenen Modulen führen kann.

  3. Man definiert die Templatefunktion in genau einem Modul, und zwingt in eben diesem Modul den Compiler durch passende Deklarationen dazu, alle nötigen Versionen zu generieren, beispielsweise:
    template<class T> T min( const T &a, const T &b )
    {
    return a<b ? a : b
    }
    int min( int, int );
    double min( double, double );
    char min( char, char );

    In allen anderen Modulen reichen dann die Deklarationen.

    Diese Vorgehensweise funktioniert gut, setzt aber voraus daß man beim Schreiben desjenigen Moduls, in dem die Definition der template-Funktion enthalten ist, bereits alle zu erzeugenden Versionen kennt. Dies ist leider nicht immer der Fall.

  4. Wenn nichts anders hilft, dann gibt es noch das Schlüsselwort export.

    Man definiert die template-Funktion in genau einem Modul, und setzt ein export davor:
    export template<class T> T min( const T &a, const T &b )
    {
    return a<b ? a : b
    }

    In den anderen Modulen wird nur noch die Deklaration (beispielsweise über eine Headerdatei) bekannt gemacht (ohne export).

    Der Compiler muß nun zusehen, wie er damit klar kommt. Das kann mehr Zeit beim Übersetzen kosten, aber es funktioniert in jedem Fall.

AnyWare@Wachtler.de