Wie gehen Sie mit immer längeren Kompilierzeiten beim Arbeiten mit Vorlagen um?

13

Ich benutze Visual Studio 2012 und er hat Fälle, in denen wir einer Klasse "nur" Vorlagenparameter hinzugefügt haben, um einen "Nahtpunkt" einzufügen, damit wir diese Teile im Komponententest durch Scheinobjekte ersetzen können.

Wie führen Sie in C ++ normalerweise Nahtpunkte ein: Verwenden von Schnittstellen und / oder Mischen basierend auf einigen Kriterien mit impliziten Schnittstellen, indem Sie auch Vorlagenparameter verwenden? Ein Grund, dies zu erfragen, liegt auch darin, dass beim Kompilieren einer einzelnen C ++ - Datei (die Vorlagendateien enthält, die auch andere Vorlagen enthalten können) eine Objektdatei generiert wird, die auf einem Entwicklercomputer in der Größenordnung von etwa 5 bis 10 Sekunden dauert .

Der VS-Compiler ist meines Wissens auch nicht besonders schnell beim Kompilieren von Vorlagen und aufgrund des Vorlageneinschlussmodells (Sie fügen praktisch die Definition der Vorlage in jede Datei ein, die sie indirekt verwendet, und instanziieren diese Vorlage möglicherweise bei jeder Änderung neu Etwas, das nichts mit dieser Vorlage zu tun hat. Sie könnten Probleme mit den Kompilierzeiten haben (beim inkrementellen Kompilieren).

Wie gehen Sie mit der inkrementellen (und nicht nur) Kompilierzeit beim Arbeiten mit Vorlagen um (neben einem besseren / schnelleren Compiler :-))?

Ghita
quelle
1
@RobertHarvey-Abhängigkeitsinjektion wird mithilfe von Vorlagenparametern durchgeführt. In Produktionscode, in dem ich diese instanziiere, habe ich langsame Kompilierzeiten.
Ghita
5
Verwenden Sie C ++ 11? siehe en.wikipedia.org/wiki/C%2B%2B11#Extern_template
mike30
2
Da Andrei Alexandrescu "Modernes C ++ - Design" geschrieben hat, denken viele C ++ - Programmierer, dass sie Vorlagen für alles und jeden verwenden müssen, und lassen den Compiler so viel wie möglich damit umgehen. Dies führt normalerweise zu den beschriebenen Effekten. Früher (und derzeit noch für Programmierer, die andere Sprachen verwenden) war es absolut in Ordnung, keine Vorlagen zu verwenden und Dinge wie Abhängigkeitsinjektion mit Laufzeitmechanik zu behandeln, selbst wenn dies einige CPU-Zyklen mehr für den Endbenutzer erfordert (was er so gut wie nie bemerken wird) ). Ganz ehrlich, ich bin mir sicher, dass Robert zu 100% korrekt ist, und so denken Sie darüber.
Doc Brown
1
@Ghita: IMHO mit Template-Metaprogrammierung ist oft nur eine Form der vorzeitigen Optimierung (und manchmal nur Overkill) - sofern Sie keine Bibliotheken wie die STL mit vergleichbaren Anforderungen schreiben. Sie tauschen einen gewissen Leistungsgewinn gegen längere Kompilierzeiten, geringere Wartbarkeit und viele schwer verständliche Fehlermeldungen aus. Die Verwendung von "externen Vorlagen" kann Ihnen kurzfristig helfen, aber wenn ich in Ihren Schuhen stecke, würde ich auch über langfristige Verbesserungen nachdenken.
Doc Brown
4
@ DocBrown. Umgekehrt könnte man sagen , dass das Vermeiden von Vorlagen zur Verbesserung der Build-Leistung eine vorzeitige Optimierung ist. Vorlagen sind die idealen Abstraktionen für viele Probleme.
mike30

Antworten:

9

Wenn Ihre Vorlagenparameter nur einen begrenzten (und kleinen) Wertesatz annehmen können, können Sie deren Definition in eine Quelldatei verschieben und eine explizite Instanziierung verwenden .

Zum Beispiel aaa.hdeklarieren Sie in nur die Template-Funktionen fund g:

template <int n>
int f();

template <class T>
void g(int a);

Es sei angenommen , nTemplate - Parameter nur 1 sein kann, 3, 6 und TTemplate - Parameter können nur sein int, longund void *.

Dann definieren Sie sie aaa.cppwie folgt:

template <int n>
int f()
{
    ...
}

template <class T>
void g(int a)
{
    ...
}

template int f<1>();
template int f<3>();
template int f<6>();

template void g<int>(int a);
template void g<long>(int a);
template void g<void *>(int a);

Auf diese Weise instanziiert der Compiler beim Kompilieren die Vorlage für die angegebenen Parameter aaa.cpp. Beim Kompilieren von Client-Code wird davon ausgegangen, dass die Definitionen irgendwo existieren, und der Linker wird sich darum kümmern.

#include "aaa.h"

int main()
{
    f<1>();
    f<3>();
    f<6>();

    g<int>(5);
    g<long>(5);
    g<void *>(5);
}

Sie können Vorlagenklassen auch explizit instanziieren. Der Nachteil ist, dass Sie nicht foder gmit anderen Template-Parametern arbeiten können.

#include "aaa.h"

int main()
{
    f<5>();
}

Ergebnisse in

undefined reference to `int f<5>()'

Ich habe diese Technik in einem Projekt verwendet, in dem nur wenige komplexe Klassen von einem kleinen Satz (<10) von Ganzzahl-Vorlagenparametern abhängig waren und die Kompilierungszeit erheblich verkürzt wurde (da der Compiler die komplexen Vorlagendefinitionen beim Kompilieren des Client-Codes nicht analysieren musste). . Natürlich können je nach aktuellem Code kleinere Verbesserungen erzielt werden.

Claudio
quelle
2

Einmal habe ich eine seltsame Lösung für ein ähnliches Problem verwendet: Das Einbeziehen der STL führte zu Kompilierzeiten von mehreren Sekunden pro Quelldatei - egal wie klein sie war. Also habe ich alle meine Quelldateien in eine Master-Datei aufgenommen und die Kompilierungszeit pro Datei hat sich kaum geändert ... was eine Steigerung um den Faktor 20+ bedeutete, da ich nur eine einzige Datei kompilieren musste.

Um das Design sauber zu halten, habe ich weiterhin ein Makefile gepflegt, es aber nie verwendet (außer, dass überprüft wurde, ob es noch funktioniert).

maaartinus
quelle
0

Früher haben wir eine große Aufgabe ausgelöst, um unsere vorkompilierten Header und vorkompilierten Vorlagen über Nacht zu erstellen und erst am nächsten Tag gegen diese zu arbeiten.

Ti Strga
quelle