2009-11-12 22 views
60

considerando sempre che la seguente intestazione, contenente la mia classe su modelli, è inclusa in almeno due .CPP file, il codice compilato correttamente:modello di specializzazione di un unico metodo da una classe template

template <class T> 
class TClass 
{ 
public: 
void doSomething(std::vector<T> * v); 
}; 

template <class T> 
void TClass<T>::doSomething(std::vector<T> * v) { 
// Do somtehing with a vector of a generic T 
} 

template <> 
inline void TClass<int>::doSomething(std::vector<int> * v) { 
// Do somtehing with a vector of int's 
} 

Ma notare che la linea nel metodo di specializzazione. È necessario che il codice non abbia errore di linker (in VS2008 è LNK2005) a causa del metodo che viene definito più di una volta. Capisco questo perché AFAIK una specializzazione di modello completo è la stessa di una semplice definizione di metodo.

Quindi, come rimuovere quello inline? Il codice non dovrebbe essere duplicato in ogni suo utilizzo. Ho cercato su Google, ho letto alcune domande qui in SO e ho provato molte delle soluzioni suggerite, ma nessuna è stata realizzata correttamente (almeno non in VS 2008).

Grazie!

+3

Perché vuoi rimuovere la linea? Lo trovi esteticamente sgradevole? Pensi che cambi il significato del tuo codice? –

+0

Perché se questo metodo fosse "long" e usato in molti posti, dovrei copiare il suo codice binario ovunque, giusto? Ho cercato di spiegarlo nella domanda, ma suppongo che non fosse chiaro ... :) – Chuim

+0

@ Martin: Che cosa succede se l'implementazione richiede molto altro codice che deve quindi essere incluso da questa intestazione invece del file cpp? – sbi

risposta

50

Come per le funzioni semplici, è possibile utilizzare la dichiarazione e l'implementazione. mettere nella vostra dichiarazione di intestazione:

template <> 
void TClass<int>::doSomething(std::vector<int> * v); 

e mettere implementazione in uno dei vostri CPP-files:

template <> 
void TClass<int>::doSomething(std::vector<int> * v) { 
// Do somtehing with a vector of int's 
} 

Non dimenticare di rimuovere in linea (ho dimenticato e ho pensato che questa soluzione non funziona:)). Controllato su VC++ 2005

+0

Ho provato qualcosa di simile a questo prima ma ho ricevuto altri errori ma ora che hai menzionato devo aver dimenticato di rimuovere 'inline' mentre copia/incolla. In questo modo ha funzionato! – Chuim

+0

Lo stesso vale per le funzioni template free (al contrario dei metodi di classe). Stavo ricevendo lo stesso errore linker per la mia specializzazione di funzione. Ho spostato il corpo della specializzazione delle funzioni in un file .cpp e ho lasciato la dichiarazione della specializzazione nell'intestazione, e tutto ha funzionato. Grazie! – aldo

+0

Mi sono appena imbattuto in questo problema, e quanto sopra lo ha risolto per me. Inoltre, è necessario occuparsi di dove il compilatore * espande * il codice del modello. Se viene eseguito due volte, il compilatore si lamenta di più definizioni. – Diederik

3

È necessario spostare la definizione di specializzazione nel file CPP. La specializzazione della funzione membro della classe template è consentita anche se la funzione non è dichiarata come modello.

+0

Questa era la direzione di cui ero già a conoscenza. Ma stavo cercando la risposta definitiva perché non stavo andando bene. – Chuim

1

Non vi è alcun motivo per rimuovere la parola chiave in linea.
Non modifica il significato del codice in alcun modo.

+0

Copiato dal commento della domanda: Perché se questo metodo fosse "lungo" e usato in molti posti, dovrei copiare il suo codice binario dappertutto, giusto? Ho cercato di spiegarlo nella domanda ma immagino che non fosse chiaro ... :) – Chuim

+0

No. Il linker rimuove qualsiasi copia extra. Quindi, all'interno di un'applicazione o di una libreria, avresti solo una volta l'istanza del metodo. –

+3

Se la parola chiave 'inline' restituisce effettivamente la funzione inline (lo standard dice che il compilatore dovrebbe prenderlo come suggerimento), allora quelle copie extra non possono essere rimosse. È, tuttavia, solo un suggerimento per inline (il suo effetto principale è quello di dire "non generare errori sulle collisioni di link in un modo particolare") – Yakk

0

Se si desidera rimuovere la linea inline per qualsiasi motivo, la soluzione di maxim1000 è perfettamente valida.

Nel tuo commento, tuttavia, sembra che tu creda che la parola chiave inline significhi che la funzione con tutti i suoi contenuti sia sempre in linea ma AFAIK che dipende in realtà dall'ottimizzazione del compilatore.

Citando dal C++ FAQ

Ci sono diversi modi per indicare che una funzione è inline, alcuni dei che coinvolgono la parola chiave inline, altri no. Indipendentemente dal modo in cui lo designa una funzione come inline, è una richiesta che il compilatore è ignorata: il compilatore potrebbe espandere in linea alcuni, tutti o nessuno dei luoghi in cui si chiama una funzione designata come inline. (Non scoraggiare se ciò sembra irrimediabilmente vago.La flessibilità dello sopra è in realtà un enorme vantaggio: consente al compilatore di trattare le grandi funzioni in modo diverso da quelle piccole, in più consente al compilatore di generare codice facilmente eseguire il debug se si seleziona il compilatore giusto opzioni.)

Quindi, a meno che non si sa che tale funzione sarà effettivamente gonfiare il tuo eseguibile o meno che si desidera rimuovere dal intestazione definizione del modello per altri motivi, si può effettivamente lasciare dove si trova, senza alcun danno

Problemi correlati