将模板类分成多个文件会产生链接问题

时间:2010-10-25 03:14:16

标签: c++ templates

我在下面创建了一个示例来说明我遇到的问题。基本上,当我将模板类分成单独的.h / .cpp文件时,我得到了构造函数的未解析符号。使用单个文件,它编译得很好。造成这种情况的原因是什么?

fruits.cpp:

#include "apple.h"

class FruitsDB {
    public:
        void addApple();
};

void FruitsDB::addApple() {
    Apple<int> m;
}

int main() {
    FruitsDB fruits;
    return 0;
}

apple.h:

template <typename T>
class Apple {
    public:
        Apple();
        ~Apple();
};

apple.cpp

template <typename T>
Apple<T>::Apple() {
}

template <typename T>
Apple<T>::~Apple() {
}

这会产生编译器错误:

g++    -c -o fruits.o fruits.cpp
g++    -c -o apple.o apple.cpp
g++ -Wall -ggdb fruits.o apple.o -o fruits
Undefined symbols:
  "Apple<int>::Apple()", referenced from:
      FruitsDB::addApple()     in fruits.o
  "Apple<int>::~Apple()", referenced from:
      FruitsDB::addApple()     in fruits.o
ld: symbol(s) not found

我认为这是导致问题的代码,但合并文件不会产生问题。我假设我需要在某个地方包含一个我不是的文件。我完全迷失了。

注意:在apple.cpp中添加template <> Apple<int>::Apple() {}将解决此问题,但我正在使用模板来避免编写所有这些构造函数等。

2 个答案:

答案 0 :(得分:4)

只需将模板函数定义放在头文件中即可。关于模板函数的事情是,它们实际上不是函数。它们是功能模板。因此,它们不能像正常函数一样在上下文之外编译。只有在模板参数已知的情况下才能编译它们。所以编译是在使用它们的文件调用函数时完成的。为了实现这一点,模板需要对调用它的文件可见,这就是你把它放在标题中的原因。

答案 1 :(得分:2)

理论上,根据当前的C ++标准,您可以通过将export关键字添加到模板来修复代码。

实际上,只有一个编译器(Comeau C ++)真正支持export,而且它的市场份额相当小。还有一些基于EDG前端的编译器也接受包含export关键字的代码,并且可能正确处理您的代码,但是没有正式支持它,所以如果它不起作用,你是独立的(例如,英特尔C ++)。由于它几乎完全没有实现(主要是因为它接近于无法实现并且似乎在任何情况下都没有提供任何实际好处),C ++标准委员会已投票决定从下一个标准中删除export

将每个模板的完整定义(直接或间接)放入头文件中,这实际上是使代码工作的唯一方法。