Moule Lin
← All notes

Template Specialization

Full specialization

template <class key>
class hash{}

template<>
class hash<char>{}

template<>
class hash<int>{}

template<>
class hash<long>{
    size_t operator() (const long x){
        return x;
    }
}

cout<< hash<long>() (100);
//first create a temporary object, then call the overloaded ()

full specialization aims to specialize some type.
for example:
this is a function for judging equality of two members

template<class T>
bool Isequal(T& p1, T& p2){
    return p1 == p2;
}

But it doesn’t work for string. We need to override this special type


template<>
bool Isequal<char*> (char* p1, char* p2){    
    return strcmp(p1, p2) == 0;
}

Note that for a function template you don’t need to write <>

template <class T>
T max(const T lhs, const T rhs){   
    return lhs > rhs ? lhs : rhs;
}

template <>
int max(const int lhs, const int rhs){   
    return lhs > rhs ? lhs : rhs;
}
//This is because the compiler can deduce from the signature int max(const int, const int) that it is a specialization of T max(const T, const T).

Note that if specialization function doesn’t have arguments. It has various interpretation. For example

template <class T>
void f(){ T d; }

template <>
void f(){ int d; }

Here the compiler does not know that f() is specialized from f<T>(), so compilation fails with:

error: no function template matches function template specialization 'f'
In this case we need to explicitly specify the "template argument":

template <class T>
void f(){ T d; }

template <>
void f<int>(){ int d; }

partial specialization

For arguments:

Like full specialization, partial specialization provides a custom template for a set of parameters, but a partially specialized template must be instantiated further before it has a concrete signature. Note that function templates cannot be partially specialized.

template <class T1, class T2>
class A<T1, T2>{
    ...
};
template <class T2>
class A<int, T2>{
    ...
};


Function templates cannot be partially specialized; the following declaration fails to compile:

template <class T1, class T2>
void f(){}

template <class T2>
void f<int, T2>(){}


But functions can be overloaded, so declaring another function template meets the need for partial specialization:

template <class T2>
void f(){}              // Note: there is no "template argument" here

In most cases, overloading function templates covers the need for partial specialization. One exception is the std namespace: std is a special namespace in which users may specialize templates but may not add templates (in fact, adding anything at all is forbidden)

For range:

template <class T>
class A{}
template <class U>
class A<U*>{}
// we limit if the type is pointer thereby goes second class

A<string> a;

A<string*> b;

The point of this design is that when pointers need different handling, this partial specialization is used