Errore di riferimento non definito per il metodo template

Questo mi ha fatto impazzire per l’ultima ora e mezza. So che è una cosa piccola ma non riesco a trovare cosa c’è che non va (il fatto che sia un piovoso venerdì pomeriggio, ovviamente, non aiuta).

Ho definito la seguente class che conterrà i parametri di configurazione letti da un file e mi consentirà di accedervi dal mio programma:

class VAConfig { friend std::ostream& operator<<( std::ostream& lhs, const VAConfig& rhs); private: VAConfig(); static std::string configFilename; static VAConfig* pConfigInstance; static TiXmlDocument* pXmlDoc; std::map valueHash; public: static VAConfig* getInstance(); static void setConfigFileName( std::string& filename ) { configFilename = filename; } virtual ~VAConfig(); void readParameterSet( std::string parameterGroupName ); template T readParameter( const std::string parameterName ); template T convert( const std::string& value ); }; 

dove il metodo convert() è definito in VAConfig.cpp as

 template  T VAConfig::convert( const std::string& value ) { T t; std::istringstream iss( value, std::istringstream::in ); iss >> t; return t; } 

Tutto abbastanza semplice. Ma quando provo dal mio programma principale usando

 int y = parameters->convert("5"); 

Ricevo un undefined reference to 'int VAConfig::convert...' all’errore di compilazione undefined reference to 'int VAConfig::convert...' . Idem per readParameter() .

Ho visto un sacco di tutorial sui modelli, ma non riesco a capirlo. Qualche idea?

L’implementazione del codice basato sui modelli non dovrebbe mai essere in un file .cpp : il compilatore deve vederli nello stesso momento in cui vede il codice che li chiama (a meno che non si usi l’istanziazione esplicita per generare il codice dell’object temporizzato, ma anche in quel caso .cpp è il tipo di file errato da utilizzare).

Quello che devi fare è spostare l’implementazione nel file di intestazione o in un file come VAConfig.t.hpp , quindi #include "VAConfig.t.hpp" ogni volta che usi qualsiasi funzione di membro #include "VAConfig.t.hpp" modello.

Se si sposta l’implementazione dei metodi basati su modelli (convert e readParameter) nel file di intestazione, dovrebbe funzionare.

Il compilatore deve avere accesso alle implementazioni delle funzioni basate su modelli nei punti in cui vengono istanziate.

Un metodo di modello è semplicemente un modello … per un metodo. Gli argomenti del template devono essere compilati dove il metodo è “istanziato”.

Dovrebbe essere ansible creare un compilatore che si accontenti della dichiarazione di un metodo di modello e avere un passaggio di ‘compilazione del modello’ compilare tutte le istanze necessarie del metodo di modello.

Questo non è il caso per microsoft’s vc. Ho sentito un collega borbottare sul fatto che sia il caso su Unix, però.

La maggior parte dei compilatori istanzia il metodo template su richiesta, dove sono utilizzati nel codice sorgente. Per istanziare il metodo, il compilatore deve ‘vedere’ il corpo della funzione template. Ecco perché il corpo viene spesso inserito nel file di intestazione o, ad esempio, in un file .h.cpp, che viene quindi incluso come ultima riga del file .h.