テンプレートについての私自身の理解に課題を見つけました。テンプレートがインスタンス化されているすべての依存型にアクセスするには、テンプレートのソースコードをヘッダーファイルに配置する必要があることを理解しています。
したがって、この例では:
// This code cannot be placed in the cpp file
template <typename T> T foo(T v)
{
return -v;
}
の本文はT foo(T v)
ヘッダーファイルに配置する必要があります。foo
関数がどこかにインスタンス化されると、「実際の」本文関数が作成され、T
シンボルが実際の型に置き換えられます。このコードで:
int bar = 5;
float baz = 6.66f;
bar = foo<int>(bar);
baz = foo<float>(baz);
テンプレートのインスタンス化メカニズムは、以前に定義されたテンプレートに基づいて次の関数を作成します。
int foo(int v)
{
return -v;
}
float foo(float v)
{
return -v;
}
ただし、テンプレートクラスがある場合、そのクラスには、依存型をまったく使用しない関数を含めることができます。
template <typename T> class Foo
{
Foo() : mistery(0), value(0) {}; // We're using the dependant type.
AddMistery() { ++mistery; }; // We are not using the dependant type.
int mistery;
T value;
};
AddMistery
このメソッドは依存型を使用していないため、このメソッドをcppファイルに配置できると最初に考えましたが、試したところ、リンク中に失敗しました。この時点で、テンプレートクラスのさまざまなインスタンスが同じクラスではないことを思い出して、顔を平手打ちしました。したがって、リンカがその仕事をしているとき、AddMistery
メソッドの本体を探しますが、irがcppファイルに配置されているため、それは見つかりません。
// Foo.h
template <typename T> class Foo
{
Foo() : mistery(0), value(0) {}; // We're using the dependant type.
AddMistery(); // We are not using the dependant type.
int mistery;
T value;
};
// Foo.cpp
#include "Foo.h"
template <typename T> Foo<T>::AddMistery()
{
++mistery;
}
// Main.cpp
#include "Foo.h"
int main(int argc, char **argv)
{
Foo<int> i;
Foo<float> f;
i.AddMistery(); // Link Error, where's the Foo<int>::AddMistery body?
f.AddMistery(); // Link Error, where's the Foo<float>::AddMistery body?
return 0;
};
それで、最後に、ここに質問があります:すべてのメソッドの本体をヘッダーファイルに保持する代わりに、型に依存しないすべてのメソッドの本体をcppに移動して、ヘッダーとcppファイルの間でテンプレートクラスを分割する方法がありますか?