Alexender C. のコメントで述べたように、コンパイル エラーの方が適切ではないでしょうか?
template <typename T> struct GateKeeper;
// Func we want to call
template <typename S, typename T> void foo (T t);
// Warpper that checks the type and forwards the call
template <typename T> inline void foo (T t)
{
//
// This call will fail for unless a specialization of
// GateKeeper for `T` is defined with a member TYPE
foo< typename GateKeeper<T>::TYPE, T > ( t );
}
//
// This declaration "allows" the type int.
template <> struct GateKeeper<int> { typedef int TYPE; };
void bar ()
{
foo (0); // Compiles
foo (0.0); // Causes error in wrapping foo
}
部分的な特殊化を使用して、特定のテンプレートの特殊化を許可できます。
// Some template type
template <typename T>
class TmplType
{
};
// This allows for specializations of TmplType
template <typename T> struct GateKeeper< TmplType<T> > { typedef int TYPE; };
void bar ()
{
TmplType<char> tt;
foo (tt); // Compiles
}
サポートしたいタイプごとに、新しい専門分野を追加します。
更新: 何が起きているか:
注:テンプレート パラメーター名を元のバージョンから変更して、少しわかりやすくしました。
コンパイラfoo(x)
が正しく特殊化できる唯一の関数への呼び出しを確認すると、 foo<T>(T)
. これは、 のすべてのテンプレート パラメータを推測できないためfoo<S,T>(T)
です。
の本体はfoo<T>(T)
、呼び出しを実際の関数に転送します。
foo< typename GateKeeper<T>::TYPE, T > ( t );
(余談: typenameをいつ使用するかについては、こちらを参照してください)
これは一度に2つのことをしています。
1 つ目は、他の関数を呼び出すために必要な 2 つのテンプレート パラメーター (S と T) を提供することです。
GateKeeper<T>
2 つ目は、この別の型としてのメンバーを使用することです。型GateKeeper<T>
は完全であり、そのメンバーを持っている必要があります。このチェックにより、許可するタイプと許可しないタイプを指定できます。
template <typename T> struct GateKeeper; // Incomplete
template <> struct GateKeeper<int> { typedef int TYPE; }; // Complete
の定義のみを提供し、 の定義を提供してGateKeeper<int>
いないためGateKeeper<double>
、 への呼び出しはfoo(0)
正しくfoo(0.0)
機能し、コンパイル エラーで失敗します。
を許可するdouble
には、明示的な特殊化を追加するだけです。
template <> struct GateKeeper<double> { typedef int TYPE; }; // double now works.