...除非调用库中的其他内容。这是一个简单的例子。非模板成员函数的显式专业化不称为
test1.cpp
#include <iostream>
void proofOfTwoLinked();
template <class T>
struct Foo
{
void bar(){ std::cout << "normal bar\n"; }
};
struct A{};
struct B{};
struct C{};
struct D{};
template <> void Foo<B>::bar(){ std::cout << "B bar\n"; }
int main()
{
Foo<A> a;
Foo<B> b;
Foo<C> c;
Foo<D> d;
a.bar();
b.bar();
c.bar();
d.bar();
//proofOfTwoLinked();
}
测试2.cpp
#include <iostream>
struct C;
template <class T>
struct Foo
{
void bar(){ std::cout << "normal bar\n"; }
};
template <> void Foo<C>::bar(){ std::cout << "C bar\n"; }
void proofOfTwoLinked()
{
std::cout << "Yup, two is linked\n";
}
如果我编译两人在一起时,程序按预期工作:
$ rm test; rm *.a; rm *.o; g++ -c test1.cpp; g++ -c test2.cpp; g++ -o test test1.o test2.o; ./test
normal bar
B bar
C bar
normal bar
如果我编译test2的,放它在一个档案中,然后将该程序与该程序进行链接... C类型的特化不会在c.bar()正所谓:
$ rm test; rm *.a; rm *.o; g++ -c test1.cpp; g++ -c test2.cpp; ar -r test2.a test2.o; g++ -o test test1.o test2.a; ./test
ar: creating test2.a
normal bar
B bar
normal bar
normal bar
但是,如果我去掉TEST1的最后一个函数调用(proofOfTwoLinked),然后重新编译,专业化是执行。
$ rm test; rm *.a; rm *.o; g++ -c test1.cpp; g++ -c test2.cpp; ar -r test2.a test2.o; g++ -o test test1.o test2.a; ./test
ar: creating test2.a
normal bar
B bar
C bar
normal bar
Yup, two is linked
这让我觉得很奇怪,而且肯定与我的期望相反。这实际上是正常的行为?也许因为在链接器搜索test2.a之前,在main()中调用的每个函数都已经存在某种形式,它将跳过该存档。有没有办法强制链接器“查看整个档案”?
我使用gcc 4.6.1和ar 2.21.53(在Ubuntu中)。
此外,很明显,如果我在test1中声明'template <> void Foo :: bar();'那么它也可以工作。我想这足以解决我在实际工作中使用的问题(即只是在头文件中声明特化)......但我仍然对它很好奇。 –
cheshirekow
除少数例外模板需要放入标题中。模板代码是在编译时需要时生成的,因此它们不能轻易打包为库(注意:某些编译器为此提供了解决方法,但它们不可移植)。 –
因此,模板本身在“标题”中(注意两个.cpp文件中的模板声明都相同,模拟标题的同时使我的文章变小)。问题是成员函数的特殊性,我猜也必须在标题中。 – cheshirekow