Come gestite tempi di compilazione sempre più lunghi quando lavorate con i template?


13

Uso Visual Studio 2012 e ha casi in cui abbiamo aggiunto i parametri dei modelli a una classe "solo" per introdurre un "punto di giuntura" in modo che nel test unitario possiamo sostituire quelle parti con oggetti finti.

Come si introducono solitamente i punti di cucitura in C ++: utilizzando le interfacce e / o il missaggio basato su alcuni criteri con interfacce implicite usando anche i parametri dei template? Un motivo per chiederlo è anche perché durante la compilazione a volte di un singolo file C ++ (che include file di modelli, che potrebbero includere anche altri modelli), viene generato un file oggetto che richiede circa 5-10 secondi su una macchina dello sviluppatore .

Anche il compilatore VS non è particolarmente veloce nella compilazione di modelli per quanto ne so, e a causa del modello di inclusione dei modelli (praticamente includi la definizione del modello in ogni file che lo utilizza indirettamente e possibilmente ri-istanziare quel modello ogni volta che modifichi qualcosa che non ha nulla a che fare con quel modello) potresti avere problemi con i tempi di compilazione (quando si esegue la compilazione incrementale).

Quali sono i tuoi modi di gestire il tempo di compilazione incrementale (e non solo) quando lavori con i template (oltre a un compilatore migliore / più veloce :-)).


1
L'iniezione di dipendenza @RobertHarvey viene effettuata utilizzando i parametri del modello. Nel codice di produzione in cui ho istanziato questi ho tempi di compilazione lenti.
Ghita,


2
Poiché Andrei Alexandrescu ha scritto "Modern C ++ design", molti programmatori di C ++ pensano di dover usare i modelli per tutto e tutto e lasciare che il compilatore gestisca il più possibile. Questo di solito porta a quegli effetti che stai descrivendo. In precedenza (e attualmente ancora per i programmatori che usano altre lingue), era assolutamente ok non usare modelli e gestire cose come l'iniezione di dipendenza con la meccanica del tempo di esecuzione, anche quando ciò ha bisogno di alcuni cicli della CPU in più per l'utente finale (che non noterà quasi mai ). Onestamente, sono sicuro che Robert abbia ragione al 100% e questo è il modo in cui ci pensi.
Doc Brown,

1
@Ghita: IMHO che utilizza la meta-programmazione di template è spesso solo una forma di ottimizzazione prematura (e talvolta solo eccessiva) - nella misura in cui non si scrivono librerie come la STL con requisiti comparabili. Contrattate alcuni miglioramenti delle prestazioni per tempi di compilazione maggiori, minore manutenibilità e molti messaggi di errore difficili da comprendere. L'uso di "modelli esterni" può aiutarti ora a breve termine, ma se fossi nei tuoi panni, penserei anche a miglioramenti a lungo termine.
Doc Brown,

4
@DocBrown. Al contrario, si potrebbe dire che evitare modelli per migliorare le prestazioni della build è un'ottimizzazione prematura. I modelli sono le astrazioni ideali per molti problemi.
mike30,

Risposte:


9

Se i parametri dei modelli possono assumere solo un insieme finito (e piccolo) di valori, è possibile spostare la loro definizione in un file di origine e utilizzare un'istanza esplicita .

Ad esempio, in aaa.hte dichiari solo le funzioni del modello fe g:

template <int n>
int f();

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

Si supponga nmodello di parametro può essere solo 1, 3, 6, e Tparametro di modello può essere solo int, longe void *.

Quindi li definisci in aaa.cppquesto modo:

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);

In questo modo il compilatore crea un'istanza del modello per i parametri dati durante la compilazione aaa.cpp. Quando si compila il codice client, si presume che le definizioni esistano da qualche parte e che il linker se ne occuperà.

#include "aaa.h"

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

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

Puoi anche istanziare esplicitamente le classi di template. Lo svantaggio è che non è possibile utilizzare fo gcon altri parametri del modello.

#include "aaa.h"

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

risultati in

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

Ho usato questa tecnica in un progetto in cui poche classi complesse dipendevano da un piccolo (<10) set di parametri del modello intero e ha ridotto significativamente i tempi di compilazione (poiché il compilatore non ha dovuto analizzare le definizioni complesse del modello durante la compilazione del codice client) . Ovviamente potresti ottenere miglioramenti minori, a seconda del codice effettivo.


2

Una volta ho usato una strana soluzione per un problema simile: Includere il comando STL per compilare tempi come diversi secondi per file di origine - non importa quanto fosse piccolo. Quindi ho incluso tutti i miei file sorgente in un unico file master e il tempo di compilazione per file non è cambiato quasi mai ... il che significava una velocità del fattore 20+ poiché avevo solo un singolo file da compilare.

Per mantenere pulito il design ho continuato a mantenere un makefile, ma non l'ho mai effettivamente usato (tranne per la verifica che funzioni ancora).


0

Abbiamo usato per eseguire una grande attività per costruire le nostre intestazioni precompilate e modelli precompilati durante la notte, e costruire contro quelli il giorno seguente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.