インスタンス化を避けるためにexternテンプレート(C++11)を使用する 質問する

インスタンス化を避けるためにexternテンプレート(C++11)を使用する 質問する

図1:関数テンプレート

テンプレートヘッダー.h

template<typename T>
void f();

テンプレートCpp.cpp

template<typename T>
void f(){
   //...
}    
//explicit instantation
template void f<T>();

メイン.cpp

#include "TemplHeader.h"
extern template void f<T>(); //is this correct?
int main() {
    f<char>();
    return 0;
}

これは正しい使用方法でしょうかextern template、それとも図 2 のようにクラス テンプレートにのみこのキーワードを使用するのでしょうか?

図2:クラステンプレート

テンプレートヘッダー.h

template<typename T>
class foo {
    T f();
};

テンプレートCpp.cpp

template<typename T>
void foo<T>::f() {
    //...
}
//explicit instantation
template class foo<int>;

メイン.cpp

#include "TemplHeader.h"
extern template class foo<int>();
int main() {
    foo<int> test;
    return 0;
}

これらすべてを 1 つのヘッダー ファイルに入れるのが良いことはわかっていますが、複数のファイルで同じパラメーターを持つテンプレートをインスタンス化すると、同じ定義が複数作成され、コンパイラーはエラーを回避するためにそれらをすべて (1 つを除く) 削除します。 はどのように使用すればよいですかextern template? クラスにのみ使用できますか、それとも関数にも使用できますか?

また、図 1 と図 2 は、テンプレートが 1 つのヘッダー ファイルにあるソリューションに拡張される可能性があります。その場合、extern template複数の同じインスタンス化を回避するために、キーワードを使用する必要があります。これはクラスまたは関数にのみ適用されますか?

ベストアンサー1

extern templateコンパイラに強制的に実行させる場合にのみ使用してください。ないテンプレートをインスタンス化するあなたが知っている別の場所でインスタンス化されることを意味します。これは、コンパイル時間とオブジェクト ファイルのサイズを削減するために使用されます。

例えば:

// header.h

template<typename T>
void ReallyBigFunction()
{
    // Body
}
// source1.cpp

#include "header.h"
void something1()
{
    ReallyBigFunction<int>();
}
// source2.cpp

#include "header.h"
void something2()
{
    ReallyBigFunction<int>();
}

これにより、次のオブジェクト ファイルが生成されます。

source1.o
    void something1()
    void ReallyBigFunction<int>()    // Compiled first time

source2.o
    void something2()
    void ReallyBigFunction<int>()    // Compiled second time

両方のファイルがリンクされている場合、一方void ReallyBigFunction<int>()が破棄され、コンパイル時間とオブジェクト ファイルのサイズが無駄になります。

externコンパイル時間とオブジェクトファイルのサイズを無駄にしないために、テンプレート関数をコンパイルしないようにするキーワードがあります。これを使用してください。あなたが知っている場合のみ同じバイナリのどこか他の場所で使用されます。

変更source2.cpp後:

// source2.cpp

#include "header.h"
extern template void ReallyBigFunction<int>();
void something2()
{
    ReallyBigFunction<int>();
}

次のオブジェクト ファイルが生成されます。

source1.o
    void something1()
    void ReallyBigFunction<int>() // compiled just one time

source2.o
    void something2()
    // No ReallyBigFunction<int> here because of the extern

これら両方がリンクされると、2 番目のオブジェクト ファイルは最初のオブジェクト ファイルのシンボルを使用するだけです。破棄する必要がなく、コンパイル時間とオブジェクト ファイル サイズの無駄も発生しません。

これはプロジェクト内でのみ使用する必要があります。たとえば、テンプレートを複数回使用する場合は、 1 つのソース ファイルを除くすべてのソース ファイルでvector<int>使用する必要があります。extern

これは、クラスと関数、さらにはテンプレート メンバー関数にも適用されます。

おすすめ記事