我有这个函数声明:
template<class T>
a::A& a::A::operator<<(T out) {
std::cout << out;
return (*this);
}
和这个函数定义:
namespace a {
...
class A {
...
template<class T> A& operator<<(T);
我称之为:
a::A b;
b << 1;
这是Makefile:
app: main.o A.o
g++ main.o A.o -o app
main.o: main.cpp
g++ -c main.cpp
A.o: A.cpp
g++ -c A.cpp
它给了我:
未定义的符号:a :: A&amp;一个:: A ::运营商LT;&LT; &LT; INT&GT;(int)的
为什么会这样?
答案 0 :(得分:4)
在T
表示的类型(即您的情况下为int
)实际上已知时,函数模板将在编译时变为实际函数。但是,在main.cpp
编译之前不是这种情况。在编译A.cpp
时,模板函数未实例化为实际函数,因此生成的目标文件不包含函数的二进制版本。
有两种方法可以解决这个问题。
在头文件中包含函数定义。也就是说,制作
template<class T>
a::A& a::A::operator<<(T out) {
std::cout << out;
return (*this);
}
头文件的一部分,并从.cpp
文件中删除函数定义。
这样做的结果是包含此标头的任何 .cpp
文件将能够使用模板的任何实例化,即对于任何值T
。
或者,在A.cpp
中包含显式模板实例化语句:
template a::A& a::A::operator<<(int out);
这将导致编译器在编译A.cpp
时实际实例化模板,并将编译的函数包含在目标文件中。因此链接器可以在将main.o
和A.o
链接在一起时找到它,一切都很好。缺点是它只适用于您为其提供显式实例化的特定类型(在这种情况下,只有int
)。
答案 1 :(得分:-1)
尝试将您的定义更改为:
template<class T>
a::A& a::A::operator<< <T> (T out) {
std::cout << out;
return (*this);
}
(确保它在头文件中)