大丈夫ですか。クラステンプレートの仮想関数をその本体の外側で定義するには?仮想関数をインライン化することはできませんが、コンパイル単位での複数の定義を避けるために、それらはinline
とマークされます(テンプレートヘッダーが複数のソースファイルに含まれると想定)。一方、コンパイラはinline
を自由に無視できるため、これは有効と思われます。例として、以下のコードは正しいですか?
_template <typename T>
class C
{
public:
virtual void f(T val);
};
template <typename T>
inline
void C<T>::f(T val)
{
//definition
}
_
?
ところで、gcc(3.4.2)では、関数f(T val)
の定義の前にinline
を省略できますが、通常のクラスの類似関数の前には省略できません。それはgccの振る舞いだけですか?
はい、inline
がなくても問題ありません。通常のメンバー関数と静的変数でも同じように機能します。
// everything in the header:
template <class T>
class A
{
static int i;
};
template <class T>
int A<T>::i=0;
標準見積もり:(3.2/5)
クラスタイプ(第9項)、列挙型(7.2)、外部リンケージを使用したインライン関数(7.1.2)、クラステンプレート(第14項)、非静的関数テンプレート(14.5.6)には複数の定義があります。 、クラステンプレートの静的データメンバー(14.5.1.3)、クラステンプレートのメンバー関数(14.5.1.1)、または一部のテンプレートパラメータが指定されていないテンプレートの特殊化(14.7、14.5.5) )プログラム内で、各定義が異なる翻訳単位で表示され、定義が次の要件を満たしている場合...
要件は基本的に、2つの定義が同一でなければならないと言っています。
通常のクラスの場合は機能しません。プログラム全体で最大で1つの定義が必要です。
class
を使用せずに、また複数の定義エラーを受け取らずに、同じヘッダーでinline
定義の外側にテンプレートメソッドを定義できます。
これは、テンプレート関数が完全に特殊化されていない場合、定義自体を生成しないためです。私の主張を証明するために、次のことを行います。
void C<int>::f(int)
{
}
この場合、関数には定義があるため、リンカーエラーが発生します。 (これを複数の翻訳単位に含める場合。インラインでマークする場合:
inline void C<int>::f(int)
{
}
エラーは発生しなくなりました。
問題の関数をインスタンス化する必要のあるコードが、コンパイル時(リンク時ではなく)にそのコードを可視化できる限り、そこで関数を定義できます。
テンプレート化されていない関数とその実装の場合と同様に、テンプレートを2つのファイルに分割することは非常に一般的です。1つは従来のヘッダーで、もう1つは実装です。唯一の違いは、使用するときにテンプレート実装ファイルとヘッダーを#includeする必要があることです。