...除非調用庫中的其他內容。這是一個簡單的例子。非模板成員函數的顯式專業化不稱爲
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