これは常に正当なC++でした。
14.5.6/2:
関数テンプレートは、他の関数テンプレートとし、通常の(非テンプレート)機能をオーバーロードすることができます。通常の機能は、潜在的に生成される機能テンプレートの専門化と同じ名前およびタイプを有する場合であっても、機能テンプレートに関連しない(すなわち、専門化であるとは決して考えられない)。
add<int>
のような「template-id」構文を使用すると、十分なテンプレートパラメータを持つテンプレート関数のみが考慮されます。だからa.add<int>()
は、テンプレート以外のテンプレートadd
が一致するかどうかを調べていません。
識別子がプレーン関数と関数テンプレートの両方に名前を付けると、コンパイラは関数テンプレートのテンプレート引数を推定し、テンプレート関数の特殊化を取得しようとします。その後、すべてのプレーン関数とすべてのテンプレート関数の特殊化は、通常の関数のオーバーロードロジックによって比較されます。 [13.3.1/7を参照]
この例では、a.add()
というコールは、テンプレートバージョンのテンプレート引数T
を推定できません。したがって、唯一実行可能な機能はテンプレート以外のオーバーロードです。
同様の状況で起こるもう1つのルールもあります。テンプレート以外の関数とテンプレート関数の特殊化があいまいなオーバーロードの場合、テンプレート以外の関数が勝ちます。 [このルールは、1つの引数のセットに対して別のより良い機能するものの定義の途中で、セクション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;
}
テンプレートがまだで使用することができますので、これは理にかなっています他の特殊化、または山括弧>
を明示的に使用して、したがって、テンプレート以外の関数を使って関数テンプレートをオーバーロードすることは、明示的な特殊化を追加するようなものですが、頭痛が少なくなります。
うわー、後者はさらに面白いです - これを念頭に置いておきます、ありがとう! –