2009-07-10 47 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文件的最后一行。