2009-07-10 26 views
36

這讓我在過去的一個半小時內生氣。我知道這是一件小事,但無法找到問題所在(事實上,這是一個下雨的星期五下午,當然,這沒有幫助)。模板方法未定義的參考錯誤

我已經定義了下面的類,將舉行從文件中讀取配置參數,並讓我從我的程序訪問它們:

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); 
}; 

其中方法convert()VAConfig.cpp被定義爲

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

所有很簡單。但是,當我從我的主程序測試使用

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

我收到undefined reference to 'int VAConfig::convert<int>...'編譯錯誤。同上readParameter()

考察了很多模板,教程,但不需經過不知道這一點。有任何想法嗎?

+2

一個半小時並沒有那麼糟......它昨天殺了我3。 – 2012-08-16 16:24:09

回答

55

爲模板的代碼實現不應該在一個.cpp文件:你的編譯器必須看到他們在同一時間,因爲它認爲調用它們(除非你使用explicit instantiation生成模板對象代碼的代碼,但即使是這樣.cpp是錯誤的文件類型使用)。

只要使用任何模板化成員函數,您需要做的就是將實現移至頭文件或文件(如VAConfig.t.hpp),然後將#include "VAConfig.t.hpp"移至文件中。

+0

感謝Seth和Dominic,我將這些實現移到了頭文件中,它工作正常。我從未看過我讀過的任何教程中提到的這個方面。那麼,爲什麼編譯器需要在看到調用它們的代碼的同時看到實現,即在這方面是什麼使得模板化的函數是唯一的? – recipriversexclusion 2009-07-10 19:24:11

+2

編譯器需要在實例化完整模板定義時才能使用 - 以便它可以替換模板參數並對其進行評估。 如果您的編譯器支持它,您可以將模板聲明爲「extern」,並以與其他成員相同的方式使用它,但需要花費額外的鏈接時間工作。 GCC支持這個擴展。它將成爲C++ 0x標準的一部分。 – greyfade 2009-07-10 19:58:27

9

如果移動的模板方法的實現(轉換和readParameter)的頭文件,它應該工作。

編譯器必須能夠訪問在他們那裏實例化點模板函數的實現。

5

模板方法僅僅是一個方法的模板。模板參數將被填充到方法「實例化」的地方。

應該有可能建立一個編譯器,該內容與模板方法的聲明,並有一個「模板編譯」步編譯模板方法的所有所需的實例。

這不是微軟的VC的情況。儘管如此,我聽到一個同事在喃喃自己說unix是這種情況。

大多數編譯器實例化的要求,在那裏它們被在源代碼中所使用的模板的方法。爲了實例化該方法,編譯器必須'看見'模板函數體。這就是爲什麼身體最經常放置在頭文件中或者例如一個.h.cpp文件,然後將其作爲.h文件的最後一行。