0

...ライブラリから何か他のものが呼び出されない限り。これは最小限の例です。

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();
}

test2.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";
}

2 つを一緒にコンパイルすると、プログラムは期待どおりに動作します。

$ 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バー」が表示されません。test1.cpp と test2.cpp は別々のコンパイル ユニットであり、もう一方に含まれる特殊化の前方宣言がないため、これは予想どおりです。 bar" を使用しているものは何も表示されないためです。

proofOfTwoLinked(); のコメントを外すと、「proofOfTwoLinked()」が前方宣言されているため、「はい、2つリンクされています」と表示されます。test1.cppで前方宣言されていないため、期待どおりの「Cバー」をまだ取得できません

再度コンパイルすると、追加

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

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 を参照として使用しました。参考になるかもしれません。

于 2013-02-07T08:51:00.927 に答える