2009-07-10 18 views
36

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).Errore di riferimento non definito per metodo modello

ho definito la classe seguente che conterrà i parametri di configurazione letti da un file e mi lascia loro l'accesso 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<std::string, std::string> valueHash; 

public: 
    static VAConfig* getInstance(); 
    static void setConfigFileName(std::string& filename) { configFilename = filename; } 
    virtual ~VAConfig(); 

    void readParameterSet(std::string parameterGroupName); 
    template<typename T> T readParameter(const std::string parameterName); 
    template<typename T> T convert(const std::string& value); 
}; 

in cui il metodo convert() è definito in VAConfig.cpp come

template <typename T> 
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 prova dal mio programma principale utilizzando

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

ottengo un errore undefined reference to 'int VAConfig::convert<int>...' compilazione. Idem per readParameter().

Guardato un sacco di tutorial modello, ma non è possibile capirlo. Qualche idea?

+2

Un'ora e mezza non è così male ... mi ha ucciso per 3 ieri. –

risposta

55

implementazione del codice su modelli non dovrebbe mai essere in un file .cpp: il compilatore deve vedere loro allo stesso tempo come meglio crede il codice che li chiama (a meno che non si utilizza explicit instantiation per generare il codice oggetto basato su modelli, ma anche allora .cpp è il tipo di file sbagliato da usare).

È necessario spostare l'implementazione sul file di intestazione o su un file come VAConfig.t.hpp e quindi su #include "VAConfig.t.hpp" ogni volta che si utilizzano funzioni di membri con modelli.

+0

Grazie a Seth e Dominic, ho spostato le implementazioni sul file di intestazione e ha funzionato. Non ho mai visto questo aspetto menzionato in nessun tutorial che ho letto. Quindi, perché il compilatore deve vedere l'implementazione nello stesso istante in cui vede il codice che li chiama, cioè cosa rende le fusioni a modelli uniche in questo senso? – recipriversexclusion

+2

Il compilatore deve avere a disposizione l'intera definizione del modello quando lo istanzia, in modo che possa sostituire i parametri del modello e valutarlo. Se il tuo compilatore lo supporta, puoi dichiarare il tuo modello come "extern" e usarlo come faresti con qualsiasi altro membro, a costo di lavoro aggiuntivo per il collegamento. GCC lo supporta come estensione. Farà parte dello standard C++ 0x. – greyfade

+0

Esistono tecniche per tenere lontani i modelli, ovvero inoltrare le specializzazioni dei modelli di dichiarazione. -1 per "non dovrebbe mai" –

9

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 sui modelli nei punti in cui vengono istanziati.

5

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

Dovrebbe essere possibile creare un compilatore che si accontenti della dichiarazione di un metodo modello e avere un passaggio 'compilazione modello' compilare tutte le istanze necessarie del metodo 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 di modello su richiesta, dove vengono 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 es. un file .h.cpp, che viene quindi incluso come ultima riga del file .h.

+0

Quello che stai descrivendo è un "modello esterno". È incluso nella prossima versione dello standard C++ ed è stato supportato da GCC per un lungo periodo (come estensione). Visual C++ dovrebbe supportarlo nella beta corrente della prossima versione. – greyfade

+0

@greyfade: Grazie! – xtofl

+0

.h.cpp o .hpp? – Naveen

Problemi correlati