method Memorizzazione delle definizioni di funzioni modello C++ in un file.CPP




parameter template c++ (9)

Ho un codice di modello che preferirei avere memorizzato in un file CPP anziché inline nell'intestazione. So che questo può essere fatto purché tu sappia quali tipi di template saranno usati. Per esempio:

.h file

class foo
{
public:
    template <typename T>
    void do(const T& t);
};

file .cpp

template <typename T>
void foo::do(const T& t)
{
    // Do something with t
}

template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);

Nota le ultime due righe: la funzione modello foo :: do viene utilizzata solo con ints e std :: stringhe, quindi tali definizioni significano che l'app si collegherà.

La mia domanda è - è un brutto scherzo o funzionerà con altri compilatori / linker? Sto solo usando questo codice con VS2008 al momento, ma vorrò portarlo in altri ambienti.


Answer #1

Il problema che descrivi può essere risolto definendo il modello nell'intestazione o tramite l'approccio che descrivi sopra.

Raccomando di leggere i seguenti punti dalle FAQ del C ++ Lite :

Entrano in molti dettagli su questi (e altri) problemi di modello.


Answer #2

Sì, questo è il modo standard per eseguire un'istanza esplicativa speciale . Come hai affermato, non puoi creare un'istanza di questo modello con altri tipi.

Modifica: corretta in base al commento.


Answer #3

Per gli altri su questa pagina chiedendo quale sia la sintassi corretta (come ho fatto io) per la specializzazione esplicita del template (o almeno in VS2008), è la seguente ...

Nel tuo file .h ...

template<typename T>
class foo
{
public:
    void bar(const T &t);
};

E nel tuo file .cpp

template <class T>
void foo<T>::bar(const T &t)
{ }

// Explicit template instantiation
template class foo<int>;

Answer #4

Questo codice è ben formato. Devi solo prestare attenzione che la definizione del modello è visibile nel punto di istanziazione. Per citare lo standard, § 14.7.2.4:

La definizione di un modello di funzione non esportato, un modello di funzione membro non esportato o una funzione membro non esportata o membro dati statici di un modello di classe deve essere presente in ogni unità di traduzione in cui viene esplicitamente istanziata.


Answer #5

Il tuo esempio è corretto ma non molto portabile. C'è anche una sintassi leggermente più pulita che può essere usata (come sottolineato da @ namespace-sid).

Supponiamo che la classe basata su modelli sia parte di una libreria che deve essere condivisa. Dovrebbero essere compilate altre versioni della classe basata su modelli? Il manutentore della biblioteca dovrebbe anticipare tutti gli usi possibili della classe nella classe?

Un approccio alternativo è una leggera variazione su ciò che hai: aggiungi un terzo file che è il file di implementazione / istanziazione del modello.

foo.h file

// Standard header file guards omitted

template <typename T>
class foo
{
public:
    void bar(const T& t);
};

file foo.cpp

// Always include your headers
#include "foo.h"

template <typename T>
void foo::bar(const T& t)
{
    // Do something with t
}

foo-impl.cpp file

// Yes, we include the .cpp file
#include "foo.cpp"
template class foo<int>;

L'unica avvertenza è che è necessario dire al compilatore di compilare foo-impl.cpp invece di foo.cpp poiché la compilazione di quest'ultimo non fa nulla.

Naturalmente, è possibile avere più implementazioni nel terzo file o disporre di più file di implementazione per ogni tipo che si desidera utilizzare.

Ciò consente molta più flessibilità quando si condivide la classe basata su modelli per altri usi.

Questa impostazione riduce anche i tempi di compilazione per le classi riutilizzate perché non stai ricompilando lo stesso file di intestazione in ogni unità di traduzione.


Answer #6

Tempo per un aggiornamento! Crea un file inline (.inl, o probabilmente qualsiasi altro) e copia semplicemente tutte le tue definizioni in esso. Assicurati di aggiungere il template sopra ogni funzione ( template <typename T, ...> ). Ora invece di includere il file di intestazione nel file inline fai il contrario. Includere il file inline dopo la dichiarazione della classe ( #include "file.inl" ).

Non so davvero perché nessuno ha menzionato questo. Non vedo alcun inconveniente immediato.


Answer #7

Questo dovrebbe funzionare bene ovunque siano supportati i template. L'istanziazione esplicita del template è parte dello standard C ++.


Answer #8

C'è, nell'ultimo standard, una parola chiave ( export ) che potrebbe aiutare ad alleviare questo problema, ma non è implementata in nessun compilatore di cui sono a conoscenza, oltre a Comeau.

Vedi le FAQ-lite su questo.


Answer #9

Questo non è sicuramente un brutto scherzo, ma devi essere consapevole del fatto che dovrai farlo (la specializzazione esplicita del modello) per ogni classe / tipo che desideri utilizzare con il modello specificato. In caso di tipi MANY che richiedono l'istanziazione del template, ci possono essere MOLTE linee nel tuo file .cpp. Per ovviare a questo problema è possibile avere un TemplateClassInst.cpp in ogni progetto che si utilizza in modo da avere un maggiore controllo su quali tipi verranno istanziati. Ovviamente questa soluzione non sarà perfetta (aka silver bullet) in quanto potresti finire per rompere l'ODR :).





templates