2

テンプレートの宣言と実装を分離するために、次のパターンを使用しています。


decl.h (宣言)

template <typename T>
struct Foo
{
  void DoIt();
}

impl.cpp (実装)

template <typename T>
void Foo<T>::DoIt() { // impl code 
};

template class Foo<int>;
template class Foo<float>;

今、Fooに新しいメソッドを追加したいのですが、impl.cppファイルはすでに巨大なので、別のファイルimpl2.cppに移動したいです。


decl.h (宣言)

template <typename T>
struct Foo
{
  void DoIt();
  void RemoveIt();
}

impl.cpp (実装)

template <typename T>
void Foo<T>::DoIt() { // impl code 
};

template class Foo<int>;
template class Foo<float>;

impl2.cpp (実装)

template <typename T>
void Foo<T>::RemoveIt() { // impl code 
};

template class Foo<int>;
template class Foo<float>;

ここでの主な懸念はインスタンス化の重複です。どうすればそれらを回避できますか?

4

2 に答える 2

1

T一般的なテンプレート引数の実装をヘッダーに、明示的なインスタンス化をintソースfloatファイルに含める必要があります。

// decl.h
template <typename T>
struct Foo
{
  void DoIt();
  void RemoveIt();
}

#include "impl1.ipp"
#include "impl2.ipp"

// impl1.ipp
template <typename T>
void Foo<T>::DoIt() { // impl code 
};

// impl2.ipp
template <typename T>
void Foo<T>::RemoveIt() { // impl code 
};

// inst.cpp
#include "decl.h"
template class Foo<int>;   // explicit instantiation goes in source file
template class Foo<float>; // explicit instantiation goes in source file

// main.cpp
#include "decl.h"

int main()
{
    // call with concrete template arguments
    Foo<int>::DoIt();
    Foo<float>::RemoveIt();
}

なんで?DoItとは関数テンプレートであり、関数ではないため、テンプレートが渡されるRemoveIt前にコンパイルすることはできません。Tしたがって、すべてのクライアントはFoo、ヘッダーだけでなく実装ファイルも含める必要があります。最も便利な方法は、ヘッダーに実装を含めることです。そのため、名前を に変更しました.ipp

于 2012-07-14T18:53:37.597 に答える
1

次のようにします。

  1. の定義をFoo<T>::DoIt()ImplDoIt.h という名前のヘッダー ファイルに移動します (必ずしも decl.h と同じディレクトリにあるとは限りません)。
  2. 同じFoo<T>::RemoveIt()- ImplRemoveIt.h
  3. これらすべてのヘッダー ファイルを impl.cpp に含め、テンプレートをインスタンス化します。
于 2012-07-14T20:16:55.950 に答える