【问题标题】:Undefined reference error for template method [duplicate]模板方法的未定义引用错误[重复]
【发布时间】:2010-11-09 19:59:12
【问题描述】:

在过去的一个半小时里,这一直让我发疯。我知道这是一件小事,但找不到问题所在(当然,周五下午下雨,这无济于事)。

我已经定义了以下类,它将保存从文件中读取的配置参数,并允许我从我的程序中访问它们:

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&lt;int&gt;...' 编译错误。 readParameter() 同上。

查看了很多模板教程,但无法弄清楚这一点。有什么想法吗?

【问题讨论】:

  • 一个半小时还不错......昨天它杀死了我 3 个。

标签: c++ templates compilation linker


【解决方案1】:

模板化代码实现永远不应该在.cpp 文件中:您的编译器必须在看到调用它们的代码的同时看到它们(除非您使用explicit instantiation 生成模板化目标代码,但即使那么.cpp 是使用错误的文件类型)。

您需要做的是将实现移至头文件或VAConfig.t.hpp 等文件,然后在使用任何模板化成员函数时移至#include "VAConfig.t.hpp"

【讨论】:

  • 感谢 Seth 和 Dominic,我将实现移到了头文件中,并且成功了。我从未在我阅读的任何教程中看到过这个方面。那么,为什么编译器需要在查看调用它们的代码的同时查看实现,即是什么让模板化函数在这方面独一无二?
  • 编译器在实例化它时需要有整个模板定义可用 - 以便它可以替换模板参数并对其进行评估。如果您的编译器支持它,您可以将您的模板声明为“extern”并像使用任何其他成员一样使用它,但需要额外的链接时工作。 GCC 支持这个作为扩展。它将成为 C++0x 标准的一部分。
  • 有一些技术可以让模板远离,即前向声明模板特化。 -1 表示“不应该”
  • 您在 2009 年回答并在 9 年后帮助了我,谢谢 :)
【解决方案2】:

如果将模板化方法(convert 和 readParameter)的实现移动到头文件,它应该可以工作。

编译器必须能够在它们被实例化的地方访问模板化函数的实现。

【讨论】:

    【解决方案3】:

    模板方法只是一个方法的模板。模板参数将填写在方法被“实例化”的地方。

    应该可以构建一个满足模板方法声明的编译器,并有一个“模板编译”步骤来编译所有需要的模板方法实例。

    微软的vc不是这样的。不过,我听到一位同事抱怨说在 unix 上就是这种情况。

    大多数编译器会根据请求实例化模板方法,并在源代码中使用它们。为了实例化该方法,编译器必须“看到”模板函数体。这就是为什么正文最常被放置在头文件中,或者在例如。 .h.cpp 文件,然后将其作为 .h 文件的最后一行包含在内。

    【讨论】:

    • 您所描述的是“外部模板”。它包含在下一版本的 C++ 标准中,并且长期以来一直受到 GCC 的支持(作为扩展)。 Visual C++ 应该在下一个版本的当前测试版中支持它。
    • .h.cpp 还是 .hpp?
    猜你喜欢
    • 1970-01-01
    • 2013-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多