C++03 には、テンプレート クラスのインスタンス化を強制するテンプレートの明示的なインスタンス化定義( ) があります。template class Foo<int>
C++11 では、テンプレート クラスの暗黙的なインスタンス化を防ぐテンプレートの明示的なインスタンス化宣言( ) があります。extern template class Foo<int>
(クラス テンプレートのインスタンス化)
コンパイル時間を短縮するために明示的なインスタンス化宣言が実際に必要な状況をシミュレートしようとしています。しかし、私はできません。この機能がなくてもすべてが機能するように見えます (または機能しません)。
次に例を示します。
//Foo.h
#pragma once
template<class T>
class Foo
{
T inst;
public:
Foo(T i);
T& get() const;
};
//Foo.cpp
#include "stdafx.h"
#include "Foo.h"
template<class T>
Foo<T>::Foo(T inst) : inst(inst) { }
template<class T>
T& Foo<T>::get() const { return inst; }
template class Foo<int>; //explicit instantiation definition
//test1.h
#pragma once
#include "Foo.h"
//This line does not work
//extern template class Foo<int>; //explicit instantiation declaration.
void baz();
//test1.cpp
#include "stdafx.h"
#include "test1.h"
void baz()
{
Foo<int> foo(10);
int i = foo.get();
}
結果は、( ) 行をコメントするかどうかに依存しません。extern template class Foo<int>;
両方の *.obj ファイルのシンボルを次に示します。
ダンプビン /SYMBOLS test1.obj
011 00000000 UNDEF notype () 外部 | ??0?$Foo@H@@QAE@H@Z (public: __thiscall Foo::Foo(int))'
012 00000000 UNDEF notype () 外部 | ?get@?$Foo@H@@QBEHXZ (public: int __thiscall Foo::get(void)const )
013 00000000 SECT4 notype () 外部 | ?baz@@YAXXZ (void __cdecl baz(void))
...
ダンプビン /SYMBOLS Foo.obj
017 00000000 SECT4 notype () 外部 | ??0?$Foo@H@@QAE@H@Z (public: __thiscall Foo::Foo(int))
018 00000000 SECT6 notype () 外部 | ?get@?$Foo@H@@QBEHXZ (public: int __thiscall Foo::get(void)const )
test1.obj でUNDEFFoo<int>::Foo<int>(int)
とint Foo<int>::get(void)const
マークされていることに注意してください。これは、別の場所で解決する必要があることを意味します (つまり、Foo は 1 回だけコンパイルされました)。
試み #2:
Foo.h ファイルで完全なテンプレートを定義した場合 (明示的なインスタンス化定義なしextern template
)、役に立ちません。テンプレートは 2 回 (test1.cpp と test2.cpp の両方で) コンパイルされます。
例:
//test1.h
#pragma once
#include "Foo.h"
void baz();
//test1.cpp
#include "stdafx.h"
#include "test1.h"
void baz()
{
Foo<int> foo(10); //implicit instantiation of Foo<int>
int i = foo.get();
}
//test2.h
#pragma once
#include "Foo.h"
extern template class Foo<int>;
void bar();
//test2.cpp
#include "stdafx.h"
#include "test2.h"
void bar()
{
Foo<int> foo(10); //should refer to Foo<int> from test1.obj but IT IS NOT
int i = foo.get();
}
シンボル ダンプは次のとおりです。
ダンプビン /SYMBOLS test2.obj
01D 00000000 SECT4 notype () 外部 | ??0?$Foo@H@@QAE@H@Z (public: __thiscall Foo::Foo(int))
01E 00000000 SECT8 notype () 外部 | ?get@?$Foo@H@@QBEHXZ (public: int __thiscall Foo::get(void)const )
01F 00000000 SECT6 notype () 外部 | ?bar@@YAXXZ (void __cdecl bar(void))
ダンプビン /SYMBOLS test1.obj
01D 00000000 SECT6 notype () 外部 | ?baz@@YAXXZ (void __cdecl baz(void))
01E 00000000 SECT4 notype () 外部 | ??0?$Foo@H@@QAE@H@Z (public: __thiscall Foo::Foo(int))
01F 00000000 SECT8 notype () 外部 | ?get@?$Foo@H@@QBEHXZ (public: int __thiscall Foo::get(void)const )
両方の *.obj ファイルで Foo が提示します。
だから私の質問は、明示的なインスタンス化宣言の有用性は何ですか? それとも、テストで何かを見逃しているのでしょうか?
私はVS2013コンパイラを使用しています。