【问题标题】:Linker error 'unresolved external symbol' : working with templates链接器错误“未解析的外部符号”:使用模板
【发布时间】:2010-12-23 14:19:33
【问题描述】:

我有一个基于模板的类 [Allotter.h & Allotter.cpp]:

template <typename allotType> class Allotter {
public:
 Allotter();
 quint32 getAllotment(allotType*);
 bool removeAllotment(quint32, int auto_destruct = 0);

private:
 QVector<QPair<quint32, allotType*>> indexReg;
 int init_topIndex;
};

它的用法显示为[ActiveListener.h & ActiveListener.cpp]:

class ActiveListener: public QObject {
 Q_OBJECT

public:
 ActiveListener();

private slots:
    void processConnections();
    void readFromSocket(int);

private:
 QTcpServer* rootServer;
 QSignalMapper* signalGate;
 Allotter<QTcpSocket> TcpAllotter;
};

我没有展示完整的定义,因为它并不重要。问题是当我编译时,所有文件都能正确编译。这些文件位于 VC++ 项目中。早些时候,当我没有对Allotter 使用基于模板的方法时,一切都可以正常编译和链接。但是现在,我得到了这个错误:

1>ActiveListener.obj : error LNK2019: unresolved external symbol "public: __thiscall Allotter<class QTcpSocket>::Allotter<class QTcpSocket>(void)" (??0?$Allotter@VQTcpSocket@@@@QAE@XZ) referenced in function "public: __thiscall ActiveListener::ActiveListener(void)" (??0ActiveListener@@QAE@XZ)
1>ActiveListener.obj : error LNK2019: unresolved external symbol "public: unsigned int __thiscall Allotter<class QTcpSocket>::getAllotment(class QTcpSocket *)" (?getAllotment@?$Allotter@VQTcpSocket@@@@QAEIPAVQTcpSocket@@@Z) referenced in function "private: void __thiscall ActiveListener::processConnections(void)" (?processConnections@ActiveListener@@AAEXXZ)

令人惊讶的是,构造函数ActiveListener::ActiveListener() 根本没有引用Allotter&lt;QTcpSocket&gt;::Allotter()。然而,第二个参考确实存在。但我不明白为什么链接器无法解析这个外部符号。

错误出现之前的构建输出是:

1>Moc'ing ActiveListener.h...
1>Compiling...
1>stdafx.cpp
1>Compiling...
1>ActiveListener.cpp
1>Allotter.cpp
1>moc_ActiveListener.cpp
1>main.cpp
1>Generating Code...
1>Linking...

我不明白这是否相关,主要是因为以前所有这些都可以完美运行。只是我使用模板后出现问题。 任何帮助将不胜感激。非常感谢。

【问题讨论】:

标签: c++ templates qt4 visual-c++ linker-errors


【解决方案1】:

您不能将模板拆分为 .h 和 .cpp 文件 - 您需要将模板的完整代码放入 .h 文件中。

【讨论】:

  • @Charles:export 在现实生活中工作(使用 Comeau 编译器)。
  • 非常感谢 :D 你能告诉我为什么会这样吗?我假设每当编译器需要来自模板的特定类时,即来自 MyClass 的 MyClass,它需要有源代码来生成所需的类。我说的对吗?
  • 是的,你是对的。所有 参数化 的模板定义都必须进入 .h 文件。 未参数化的模板定义(即显式专用模板)应被视为“普通”代码,这意味着类在 .h 文件中定义,而函数和对象仅声明 i> 在 .h 文件中并在 .cpp 文件中定义。
  • @Jerry Comeau 编译器是虚幻的 :-) 此外,export 没有进入 c++0x 并且可能永远不会。
  • FYI 导出刚刚从 C++0x 中删除
【解决方案2】:

一般来说,将模板代码完全写在头文件中被认为是最佳实践。这有一个重要的技术原因:当您实例化模板时,C++ 编译器需要从该模板生成特定于您指定的模板参数的代码。如果您的模板代码完全放在标题中,则会自动为您完成。

绝对可以按照你的方式编写模板代码,并将实现放在 cpp 文件中。但是,如果您这样做,则需要显式实例化您打算使用的模板实例。

在您的情况下,您需要将以下行添加到项目中的 .cpp 文件中:

template class Allotter<QTcpSocket>;

【讨论】:

    【解决方案3】:

    由于您不能将模板实现放在 .cpp 文件中,因此将 .inl 文件用于模板实现并将它们包含在模板头文件中被认为是一种很好的做法。

    【讨论】:

      猜你喜欢
      • 2012-05-30
      • 1970-01-01
      • 2014-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多