0

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

测试1.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 中)。

4

1 回答 1

2

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

按原样编译我没有得到“C bar”。这与预期一致,因为 test1.cpp 和 test2.cpp 是单独的编译单元,并且没有前向声明另一个包含的特化 test1.cpp 将实例化其默认的“正常栏”,而 test2.cpp 不会实例化“C bar”,因为它看不到任何使用它的东西。

当我取消注释 proofOfTwoLinked(); 我得到“是的,两个已链接”,这是预期的,因为“proofOfTwoLinked()”是前向声明的。我仍然没有得到预期的“C bar”,因为它没有在 test1.cpp 中声明

当我再次编译添加

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

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

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

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

当我再次编译添加

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

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

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

必须在其定义之前。

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

于 2013-02-07T08:51:00.927 回答