30

我有一个这样声明的函数:

template <typename T> 
T read();

并定义如下:

template <typename T>
T packetreader::read() {
    offset += sizeof(T);
    return *(T*)(buf+offset-sizeof(T)); 
}

但是,当我尝试在 main() 函数中使用它时:

packetreader reader;
reader.read<int>();

我从 g++ 收到以下错误:

g++ -o main main.o packet.o
main.o: In function `main':
main.cpp:(.text+0xcc): undefined reference to `int packetreader::read<int>()'
collect2: ld returned 1 exit status
make: *** [main] Error 1

谁能指出我正确的方向?

4

4 回答 4

25

您需要使用export关键字。但是,我认为 G++ 没有适当的支持,因此您需要在标头中包含模板函数的定义,以便翻译单元可以使用它。这是因为<int>尚未创建模板的“版本”,只有<typename T>“版本”。

一个简单的方法是#include.cpp 文件。但是,这可能会导致问题,例如当 .cpp 文件中有其他函数时。它也可能会增加编译时间。

一种干净的方法是将模板函数移动到它自己的 .cpp 文件中,并将其包含在标题中使用export关键字并单独编译。

关于为什么你应该尝试将模板函数定义放在其头文件中的更多信息(并export完全忽略)。

于 2009-03-16T00:53:12.223 回答
12

问题是函数模板不是函数。它是根据需要创建函数的模板。

因此,要使模板正常工作,编译器直观地需要两条信息:模板本身,以及应该替换到其中的类型。这与函数调用不同,编译器一旦知道函数存在就可以生成函数调用。它不需要知道函数做了什么,只需要知道它的样子void Frobnicate(int, float),或者它的签名是什么。

当您声明函数模板而不定义它时,您只是告诉编译器存在这样的模板,而不是它的样子。这还不足以让编译器实例化它,它还必须能够看到完整的定义。通常的解决方案是将整个模板放在一个可以在需要的地方包含的标题中。

于 2009-03-16T01:00:41.753 回答
5

模板函数的最佳实践是在头文件中定义它们。它们是在编译时创建的,因此编译器必须有定义才能这样做。

exportfor 模板将得到更多支持时,情况并非如此,但现在它仍然几乎不能使用。

于 2009-03-16T00:58:30.917 回答
0

他们是否有任何编译器支持模板单独编译?

据我所知,通常的做法是在头文件中声明和实现模板函数

于 2009-03-16T01:01:08.180 回答