As mentioned in the comment by Alexender C., are you sure a compile error wouldn't be more suitable?
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
}
A partial specialization can be used to allow any specialization of a given template:
// 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
}
For each type that you wish to support you add a new specialization.
UPDATE: What is happening:
Note: I've changed the template parameter names from the original version to make things a bit clearer.
When the compiler sees a call to foo(x)
the only function that it can correctly specialize is foo<T>(T)
. This is because it cannot deduce all the template parameters for foo<S,T>(T)
.
The body of foo<T>(T)
forwards the call to the real function:
foo< typename GateKeeper<T>::TYPE, T > ( t );
(ASIDE: see here for description of when to use typename)
This is doing 2 things at once.
The first is to provide the 2 template parameters (S and T) which are required to call the other function.
The second is to use a member of GateKeeper<T>
as this other type. The type GateKeeper<T>
must be complete and have that member. It is this check that allows us to specify which types we want to allow and which we don't:
template <typename T> struct GateKeeper; // Incomplete
template <> struct GateKeeper<int> { typedef int TYPE; }; // Complete
As we have only provided a definition for GateKeeper<int>
and not for GateKeeper<double>
, the call to foo(0)
works correctly, and foo(0.0)
fails with a compile error.
To allow double
, we just need to add an explicit specialization for it:
template <> struct GateKeeper<double> { typedef int TYPE; }; // double now works.