问题
模板函数和模板类的声明 template.h
#ifndef TEMPLATE_H
#define TEMPLATE_H
template <typename T>
void f(T);
template <typename T>
class A {
public:
void f();
};
#endif
模板函数和模板类的定义 template.cpp
#include "template.h"
#include <iostream>
template <typename T>
void f(T)
{
std::cout << "::f" << std::endl;
}
template <typename T>
void A<T>::f()
{
std::cout << "A::f" << std::endl;
}
测试代码: main.cpp
#include "template.h"
int main()
{
f(3.14);
A<int> a;
a.f();
return 0;
}
编译结果: 编译器找不到f<double>(double) 和A<int>::f() 的定义,为什么呢?
以下为个人推测。
分析
对于一个普通的符号f ,编译器对它做的事情如下: (1) 编译时:包含f 的定义(实现) 的源文件输送给编译器,编译器会编译相关代码并将结果打包到对应的.o 里; (2) 链接时:当某处需要使用符号f ,便通过符号的声明寻找符号的实现,如果没找到某个符号的实现,就被报undefined 错误。
对于非模版的符号,编译器会如上正常执行。
但对于模板类和模板函数,由于它的符号是抽象的,如f<T>(T) 和A<T>::f() 中的T 是未知的。 所以在(1) 时不会把“符号”的实现打包到.o 。(2) 时,实例化模板时,编译器才会看到具体的符号,如f<double>(double) 和A<int>::f() ,但此时编译器需要知道符号的实现,因此会报undefined 错误。
结论
解决办法就是,把模板的定义和声明放在一个文件里。
template.h
#ifndef TEMPLATE_H
#define TEMPLATE_H
#include <iostream>
template <typename T>
void f(T);
template <typename T>
class A {
public:
void f();
};
template <typename T>
void f(T)
{
std::cout << "::f" << std::endl;
}
template <typename T>
void A<T>::f()
{
std::cout << "A::f" << std::endl;
}
#endif
测试代码: main.cpp
#include "template.h"
int main()
{
f(3.14);
A<int> a;
a.f();
return 0;
}
运行结果: 由于声明和定义写在了一起,在实例化模板时,通过符号的声明就能找到它的实现,因此链接不会出错。
|