質問はすでに回答されていますが、3 つのケースの微妙な違いに注目してみましょう。
ケース 1: 特化
ヘッダ:
template <typename T> struct Foo
{
void f() { /* stuff */ }
};
template <> void Foo<int>::f();
ソース:
template <> void Foo<int>::f() { /* ... */ }
この場合、Foo<T>::f()
は任意の に対して呼び出すことができますT
。一般的なケースの定義は、テンプレートから自動生成されます。の定義Foo<int>::f()
は提供されているものです。ヘッダーに特殊化があると、テンプレートを使用するのではなく、別のシンボルを検索する必要があることを消費するすべての翻訳単位に警告します。
ケース 2: 定義
ヘッダ:
template <typename T> struct Foo
{
void f();
};
ソース:
template <> void Foo<int>::f() { /* ... */ }
この場合、のみ Foo<int>::f()
使用できます。それ以外の場合はリンカー エラーが発生します。テンプレートには関数の定義がないため、テンプレートを使用するたびに新しいシンボルが発行Foo<int>::f()
され、示されている翻訳単位によって提供されるのは 1 つだけです。
ケース 3: 重大な誤り
ヘッダ:
template <typename T> struct Foo
{
void f() { /* stuff */ }
};
ソース:
template <> void Foo<int>::f() { /* ... */ }
の定義が複数あるため、これは 1 つの定義の規則に違反していますFoo<int>::f()
。