Besides class templates, you can also have function templates. Here you leave the type of the arguments to the function unspecified.
template <typename T>
T max( T x, T y )
if ( x > y )
Again, similar to class templates, when you call the function with a particular type, the compiler will create a function with your specified type.
int bigger = max( 2, 4 );
double bigger2 = max( 2.2, 4.6 );
Here, two separate functions will be generated. One for ints, one for doubles.
Function max, uses the ">" operator to compare values. So the compiler makes sure that whatever type you specify has overloaded this operator. If not, it will generate an error message. This is where the type safety comes into play.
One thing to notice is that function templates infer the type automatically, whereas class templates don't. With class templates, you HAVE to explicitly mention the type. But there are situations where it might be necessary to explicitly mention the types for functions also. In that case the syntax is similar... max<int>( 2, 4 );