これは常に正当な C++ でした。
14.5.6/2:
関数テンプレートは、他の関数テンプレートおよび通常の (非テンプレート) 関数でオーバーロードできます。通常の関数は、生成される可能性のある関数テンプレートの特殊化と同じ名前と型を持っていても、関数テンプレートとは関係ありません (つまり、特殊化とは見なされません)。
のような「template-id」構文を使用する場合add<int>
、十分なテンプレート パラメータを持つテンプレート関数のみが考慮されます。したがってa.add<int>()
、非テンプレートがadd
一致するかどうかも調べません。
識別子が単純な関数と関数テンプレートの両方に名前を付ける場合、コンパイラは関数テンプレートのテンプレート引数を推測して、テンプレート関数の特殊化を取得しようとします。次に、すべての単純な関数とすべてのテンプレート関数の特殊化が、通常の関数オーバーロード ロジックによって比較されます。[13.3.1/7 参照]
あなたの例では、呼び出しはテンプレート バージョンa.add()
のテンプレート引数を推測できません。T
したがって、唯一の実行可能な関数は、非テンプレート オーバーロードです。
同様の状況で発生する別のルールもあります。非テンプレート関数とテンプレート関数の特殊化があいまいなオーバーロードになる場合は、非テンプレート関数が優先されます。[このルールはセクション 13.3.3 にあり、与えられた引数のセットに対してある関数が別の関数よりも優れている理由の定義の途中にあります。]
class B
{
public:
int f(int n) { return n+1; }
template<typename T>
T f(T n) { return n; }
};
int main() {
B b;
b.f(1); // both are viable, non-template wins
b.f<int>(1); // only the template is viable
return 0;
}
<
テンプレートは他の特殊化で使用したり、山括弧を明示的に使用したりできるため、これは理にかなっています>
。したがって、非テンプレート関数で関数テンプレートをオーバーロードすることは、明示的な特殊化を追加するようなものですが、頭痛の種は少なくなります。