不调用非模板成员函数的显式专门化

时间:2013-02-06 23:52:22

标签: c++ template-specialization

...除非调用库中的其他内容。这是一个最小的例子。

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.bar()时,不执行类型C的特化:

$ 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中)。

1 个答案:

答案 0 :(得分:2)

使用MSVC2010SP1我的结果略有不同:

一起编译,因为我没有得到“C bar”。这是预期的,因为test1.cpp和test2.cpp是单独的编译单元,并且没有专门化的前向声明,另一个包含test1.cpp将实例化其默认的“普通条”,而test2.cpp将不会实例化“C”吧“因为它看不到任何使用它。

当我取消注释proofOfTwoLinked();我得到“Yup,two is linked”,这是因为“proofOfTwoLinked()”是向前声明的。我仍然没有得到“C bar”这是预期的,因为它没有在test1.cpp

中向前声明

当我再次编译时添加

template <> void Foo<C>::bar(); 

to test1.cpp我收到链接器错误,因为虽然test1.cpp编译单元现在知道有一个

template <> void Foo<C>::bar()

在某处,test2.cpp仍然不知道有人在使用它。

当我再次编译时添加

template void Foo<C>::bar();

到test2.cpp一切正常,我得到“C吧”。注意

template void Foo<C>::bar();

必须在其定义之前。

据我所知,MSVC表现正常,gcc在你的情况下表现得很奇怪。我使用http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf第14.7节作为参考,它可能会有所帮助。