请参阅以下代码,请清除我的疑问。
由于ABC是一个模板,为什么在将我的ABC类成员函数的定义放在test.cpp中时它不显示错误?
如果我将test.cpp代码放在test.h中并重新启动2,那么它可以正常工作。为什么呢?
// test.h
template <typename T>
class ABC {
public:
void foo( T& );
void bar( T& );
};
// test.cpp
template <typename T>
void ABC<T>::foo( T& ) {} // definition
template <typename T>
void ABC<T>::bar( T& ) {} // definition
template void ABC<char>::foo( char & ); // 1
template class ABC<char>; // 2
// main.cpp
#include "test.h"
int main() {
ABC<char> a;
a.foo(); // valid with 1 or 2
a.bar(); // link error if only 1, valid with 2
}
答案 0 :(得分:13)
在这两种情况下,您都在进行显式实例化。在第二种情况下,只有ABC<char>::foo
被实例化,而在第一种情况下,ABC<char>::bar
也被实例化。
另一个类似的例子可能会澄清其含义:
// test.h
template <typename T>
class ABC {
public:
void foo( T& );
void bar( T& );
};
// test.cpp
template <typename T>
void ABC<T>::foo( T& ) {} // definition
template <typename T>
void ABC<T>::bar( T& ) {} // definition
template void ABC<char>::foo( char & ); // 1
template class ABC<char>; // 2
// main.cpp
#include "test.h"
int main() {
ABC<char> a;
a.foo(); // valid with 1 or 2
a.bar(); // link error if only 1, valid with 2
}
在示例中,在main
中,编译器无法查看foo
或bar
定义,因此无法实例化方法。编译器在处理main.cpp时会很乐意接受main中的代码,因为你告诉它ABC
是一个模板并且它有这两个函数,并假设它们将在其他一些翻译中定义单元。
在包含test.cpp的转换单元中,编译器会看到两个方法定义,并且可以完全处理这两个实例(方法/类)。如果仅存在方法实例化([1]),则编译器将仅生成该方法,并且将bar
保留为未定义。因此,任何包含test.h的代码,针对已编译的test.cpp的链接以及仅使用foo
方法的代码都将进行编译和链接,但bar
的使用将由于未定义而无法链接。
显式地实例化类模板会为所有成员方法生成符号,在这种情况下,任何包含test.h的翻译单元和编译的test.cpp对象文件的链接都将编译和链接。
答案 1 :(得分:0)
(这是我的原始答案的编辑版本,由David Rodriguez的观察提示。)
#1
实例化类模板,并将其实例化所有方法。
#2
实例化该类的一个成员方法。作为其中的一部分,它必须实例化类模板,但不是所有其他方法。
如果将类型相关的错误引入bar()(例如void *x = b;
之类的语句),则可以看出差异。使用#1
时会出现编译器错误,但#2
会出错。另请注意,编译器(至少gcc)不会编译#1
后跟#2
,但会编译其中任何一个而不会编译其中任何一个,或者如果#2
后跟#1
}。
答案 2 :(得分:0)
我想你想要{}代替;在#1。