6

このコードを考えると:

//header.h
template <class T>
class Foo
{
public:
  Foo(T t) : t(t) {}
  T t;
};

//source1.cpp:
#include "header.h"
extern template class Foo<int>;
int main()
{
  Foo<int> f(42);
}

class Foo<int>私の理解では、どこにも定義がないはずなので、このプログラムはリンクすべきではありません(extern templateこれを防ぐ必要があります)。ただし、VC ++ 11(Visual Studio 2012)では、これはコンパイルおよびリンクされます。GCCでは、次のことは行いません。

source1.cpp:(.text+0x15): undefined reference to `Foo<int>::Foo(int)'

ただし、source2.cppとリンクすると、機能します(期待どおり):

#include "header.h"
template class Foo<int>;

このブログ投稿によると、externテンプレートはVC10以降サポートされているはずです。 http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx

ちなみに、Windows / Visual Studioのオブジェクトファイルに名前をリストする方法はありますか?Linuxでは次のようにします。

$ nm source1.o
U _ZN3FooIiEC1Ei      <- "U" means that this symbol is undefined.
0000000000000000 T main
4

1 に答える 1

16

C ++ 11 14.7.2/10「明示的なインスタンス化」は次のように述べています。

インライン関数とクラステンプレートの特殊化を除いて、明示的なインスタンス化宣言には、それらが参照するエンティティの暗黙的なインスタンス化を抑制する効果があります。

そして、クラステンプレートのコンストラクターFoo<T>はインラインです。VS2012は、次のようにヘッダーを構成すると、期待どおりに機能します。

//header.h
template <class T>
class Foo
{
public:
  Foo(T t);
  T t;
};

template <class T>
Foo<T>::Foo(T t) : t(t) 
{
}

コンストラクターがインラインにならないようにします。

上で引用した標準の段落には、次の注記が含まれています。

[注:明示的なインスタンス化宣言の対象であるインライン関数は、odr-used(3.2)の場合でも暗黙的にインスタンス化されるため、本文はインライン化の対象と見なされますが、アウトオブラインコピーはありません。インライン関数のは、変換ユニットで生成されます。—エンドノート]

ctorがインライン化されたときに作成されたアセンブリコードを見ると、ctorのアウトオブラインコピーがオブジェクトファイルに配置されているため(最適化をオンにして例をコンパイルした場合でもctorは呼び出されません)、MSVCは標準の意図に従っていないようです。ただし、メモは規範的ではないため、MSVCの動作は準拠していると思います。


MSVCで構築されたオブジェクトファイルからのシンボルのダンプに関する副次的な質問に関しては、dumpbinユーティリティを使用できます。

非インラインコンストラクターを使用して例をコンパイルする場合:

dumpbin /symbols test.obj

...

008 00000000 UNDEF  notype ()    External     | ??0?$Foo@H@@QAE@H@Z (public: __thiscall Foo<int>::Foo<int>(int))
             ^^^^^
...

ctorをインライン化して例をコンパイルします。

00A 00000000 SECT4  notype ()    External     | ??0?$Foo@H@@QAE@H@Z (public: __thiscall Foo<int>::Foo<int>(int))
             ^^^^^
于 2012-09-29T07:49:20.863 に答える