未使用のテンプレートクラスメソッドのオブジェクトコードは生成されますか?
質問
3つの異なる型パラメーターでインスタンス化されるC ++テンプレートクラスがあります。これらのタイプのうち1つだけに対してクラスが必要とするメソッドがあり、他の2つのタイプでは呼び出されません。
そのメソッドのオブジェクトコードは3回生成されますか(テンプレートがインスタンス化されるすべてのタイプに対して)、またはオブジェクトコードは1回のみ生成されますか(実際に使用されるタイプに対して)?
解決
クラステンプレートがインスタンス化されると仮想メンバー関数がインスタンス化されますが、非仮想メンバー関数は呼び出された場合にのみインスタンス化されます。
これは、C ++標準の[temp.inst]で説明されています(C ++ 11では、これは§ 14.7.1 / 10です。C++ 14では、§ 14.7.1です。 / 11、C ++ 17では§ 17.7.1 / 9です。以下のC ++ 17からの抜粋)
実装は、関数テンプレート、変数テンプレート、メンバーを暗黙的にインスタンス化してはなりません テンプレート、非仮想メンバー関数、メンバークラス、クラステンプレートの静的データメンバー、または
constexpr
ifステートメント(9.4.1)のサブステートメント。ただし、このようなインスタンス化が必要な場合を除きます
また、特定のテンプレートパラメータに対して一部のメンバー関数がインスタンス化できない場合でも、クラステンプレートをインスタンス化することができることに注意してください。例:
template <class T>
class Xyzzy
{
public:
void CallFoo() { t.foo(); } // Invoke T::foo()
void CallBar() { t.bar(); } // Invoke T::bar()
private:
T t;
};
class FooBar
{
public:
void foo() { ... }
void bar() { ... }
};
class BarOnly
{
public:
void bar() { ... }
};
int main(int argc, const char** argv)
{
Xyzzy<FooBar> foobar; // Xyzzy<FooBar> is instantiated
Xyzzy<BarOnly> baronly; // Xyzzy<BarOnly> is instantiated
foobar.CallFoo(); // Calls FooBar::foo()
foobar.CallBar(); // Calls FooBar::bar()
baronly.CallBar(); // Calls BarOnly::bar()
return 0;
}
BarOnly :: foo()などは存在しないため、Xyzzy :: CallFoo()はインスタンス化できませんが、これは有効です。この機能は、テンプレートメタプログラミングツールとしてよく使用されます。
ただし、「インスタンス化」は、テンプレートのサイズは、生成されるオブジェクトコードの量と直接相関しません。それはコンパイラ/リンカーの実装に依存します。
他のヒント
コンパイラと設定に依存すると思います。たとえば、MSVC6がすべてを生成したと思いますが、VS2005はそうではありません。仕様では、コンパイラーはすべきではありませんが、実際にはコンパイラーに依存します(たとえば、MSVC6のブーストには多くの回避策があります)。 / opt:refが有効な場合、リンカは参照されていない関数を削除できます(VSの場合、他のコンパイラに同等のオプションが存在します)。
通常、はい。
コンパイラが実際に知っているのは、プログラムが各クラスのインスタンスを少なくとも1つ作成できることです。しかし、それらのインスタンスをどうするかはわかりません。したがって、コードはほぼ確実に生成されます。
とはいえ、問題のメソッドが仮想ではなく、呼び出されない場合、リンカーは通常のデッドコード削除機能でそれらを削除できます。そのため、生成された(およびコンパイルされた)コードは最終的なEXEには含まれません。
また、これはすべてが同じではないため、使用されているC ++コンパイラに大きく依存します。