usando il template extern (C ++ 11)

Figura 1: modelli di funzioni

TemplHeader.h

template void f(); 

TemplCpp.cpp

 template void f(){ //... } //explicit instantation template void f(); 

main.cpp

 #include "TemplHeader.h" extern template void f(); //is this correct? int main() { f(); return 0; } 

È questo il modo corretto di usare il extern template , o devo usare questa parola chiave solo per i modelli di class come nella Figura 2?

Figura 2: modelli di class

TemplHeader.h

 template class foo { T f(); }; 

TemplCpp.cpp

 template void foo::f() { //... } //explicit instantation template class foo; 

main.cpp

 #include "TemplHeader.h" extern template class foo(); int main() { foo test; return 0; } 

So che è bene mettere tutto questo in un file di intestazione, ma se istanziamo modelli con gli stessi parametri in più file, allora abbiamo più definizioni e il compilatore le rimuoverà tutte (tranne una) per evitare errori. Come posso usare il extern template ? Possiamo usarlo solo per le classi o possiamo usarlo anche per le funzioni?

Inoltre, la Figura 1 e la Figura 2 possono essere espanse in una soluzione in cui i modelli si trovano in un singolo file di intestazione. In tal caso, dobbiamo utilizzare la parola chiave extern template per evitare più istanze uguali. Questo è solo per le classi o le funzioni?

Dovresti usare solo il extern template per forzare il compilatore a non istanziare un template quando sai che verrà istanziato da qualche altra parte. Viene utilizzato per ridurre il tempo di compilazione e la dimensione del file object.

Per esempio:

 // header.h template void ReallyBigFunction() { // Body } // source1.cpp #include "header.h" void something1() { ReallyBigFunction(); } // source2.cpp #include "header.h" void something2() { ReallyBigFunction(); } 

Ciò comporterà i seguenti file object:

 source1.o void something1() void ReallyBigFunction() // Compiled first time source2.o void something2() void ReallyBigFunction() // Compiled second time 

Se entrambi i file sono collegati insieme, void ReallyBigFunction() un void ReallyBigFunction() , con conseguente spreco di tempo di compilazione e dimensioni del file object.

Per non sprecare tempo di compilazione e dimensione del file object, esiste una parola chiave extern che rende il compilatore non compilare una funzione modello. Dovresti usare questo se e solo se sai che è usato nello stesso binario da qualche altra parte.

Cambiare source2.cpp in:

 // source2.cpp #include "header.h" extern template void ReallyBigFunction(); void something2() { ReallyBigFunction(); } 

Risulterà nei seguenti file object:

 source1.o void something1() void ReallyBigFunction() // compiled just one time source2.o void something2() // No ReallyBigFunction here because of the extern 

Quando entrambi saranno collegati insieme, il secondo file object utilizzerà semplicemente il simbolo dal primo file object. Non c’è bisogno di scartare e sprecare tempo di compilazione e dimensioni del file object.

Questo dovrebbe essere usato solo all’interno di un progetto, come nei momentjs in cui usi un template come vector più volte, dovresti usare extern in tutti i file tranne uno.

Questo vale anche per le classi e funziona come una, e anche per le funzioni dei membri del template.

Wikipedia ha la migliore descrizione

In C ++ 03, il compilatore deve creare un’istanza di un modello ogni volta che si incontra un modello completamente specificato in un’unità di traduzione. Se il modello viene istanziato con gli stessi tipi in molte unità di traduzione, ciò può aumentare notevolmente i tempi di compilazione. Non c’è modo di prevenirlo in C ++ 03, quindi C ++ 11 ha introdotto dichiarazioni di template extern, analoghe alle dichiarazioni di dati extern.

C ++ 03 ha questa syntax per obbligare il compilatore a creare un’istanza di un modello:

  template class std::vector; 

C ++ 11 ora fornisce questa syntax:

  extern template class std::vector; 

che dice al compilatore di non istanziare il modello in questa unità di traduzione.

L’avviso: nonstandard extension used...

Microsoft VC ++ aveva una versione non standard di questa funzione già da alcuni anni (in C ++ 03). Il compilatore avverte che per evitare problemi di portabilità con il codice che è necessario compilare anche su compilatori diversi.

Guarda l’esempio nella pagina collegata per vedere che funziona all’incirca nello stesso modo. Puoi aspettarti che il messaggio vada via con le versioni future di MSVC, eccetto ovviamente quando usi altre estensioni del compilatore non standard allo stesso tempo.

Il problema noto con i modelli è il gonfiore del codice, che è conseguenza della generazione della definizione di class in ogni modulo che richiama la specializzazione del modello di class. Per evitare ciò, a partire da C ++ 0x, si potrebbe usare la parola chiave extern di fronte alla specializzazione del modello di class

#include extern class CMyClass;

L’istanza esplicita della class template dovrebbe avvenire solo in una singola unità di traduzione, preferibile quella con definizione del modello (MyClass.cpp)

 template class CMyClass; template class CMyClass; 

Se hai già utilizzato extern per le funzioni, per i modelli viene seguita esattamente la stessa filosofia. in caso contrario, può essere utile andare all’esterno di funzioni semplici. Inoltre, potresti voler inserire gli esterni nel file di intestazione e includere l’intestazione quando ti serve.