21

クラステンプレートの仮想関数を本体外で定義してもよろしいですか? 仮想関数をインライン化することはできませんが、コンパイル単位で複数の定義を避けるために、それらをマークする必要があります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) ではinline、関数の定義の前を省略できますf(T val)が、通常のクラスの類似関数の前では省略できません。それはgccの振る舞いだけですか?

4

3 に答える 3

18

Yes, it's OK even without inline. It works the same for ordinary member functions and static variables:

// everything in the header:
template <class T>
class A
{
  static int i;
};

template <class T>
int A<T>::i=0;

Standard quote: (3.2/5)

There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements ...

The requirements basically say the two definitions have to be identical.

It doesn't work in case of regular classes. There has to be at most one definition in the whole program.

于 2012-04-18T14:22:16.753 に答える
10

複数の定義エラーを使用したり受け取ったりすることclassなく、同じヘッダーで定義外のテンプレートメソッドを定義できます。inline

これは、完全に特殊化されていない場合、テンプレート関数が定義自体を生成しないためです。私の主張を証明するために、次のことを行います。

void C<int>::f(int)
{
}

この場合、関数には定義があるため、リンカーエラーが発生します。(これを複数の翻訳単位に含める場合。インラインでマークする場合:

inline void C<int>::f(int)
{
}

エラーは発生しなくなりました。

于 2012-04-18T14:19:12.550 に答える
4

問題の関数をインスタンス化する必要があるコードが、(リンク時ではなく) コンパイル時にそのコードを認識できる限り、そこで関数を定義できます。

テンプレートを 2 つのファイルに分割することは非常に一般的です。一方は従来のヘッダーで、もう一方は実装であり、テンプレート化されていない関数とその実装と同様です。唯一の違いは、テンプレート実装ファイルとヘッダーを使用する場合に #include する必要があることです。

于 2012-04-18T14:18:53.237 に答える