Suppose we have the following function
int compare(const string &v1,const string &v2) { if(v1<v2)return -1; if(v1>v2)return 1; return 0; }
This function compares two values and indicates the greater than, less than, or equal relationship between the two values.
1. Function template
1.
template<typename T> int compare(const T&v1,const T&v2) { if(v1<v2)return -1; if(v1>v2)return 1; return 0; }
2. Use function template
int main() { //T is int cout<<compare(1,0)<<endl; //T is a string string s1="hi",s2="world"; cout<<compare(s1,s2)<<endl; return 0; }
3.inline function template
The inline keyword is placed after the template and before the function type
//Correct writing template<typename T>inline T min(const T&,const T&) //Wrong writing inline template<typename T>T min(const T&,const T&)
2. Class template
1. Definitions
template<class Type>class Queue{ public: Queue(); Type &front(); const Type &front()const; void push(const Type &); void pop(); bool empty()const private: ... };
2. Use class template
In contrast to using function templates (1.2), when using class templates, you must explicitly specify arguments for template formal parameters
queue<int>qi; Queue<vector<double>>qc; Queue<sting>qs;
template specialization
Sometimes the template definitions we write do not always apply to all types
template<typename T> int compare(const T&v1,const T&v2) { if(v1<v2)return -1; if(v1>v2)return 1; return 0; }
When the parameter type of this function is C-style string, this function cannot work normally (this function will compare the relative positions of two pointers in memory, but does not compare the size of the pointer pointing to the object). At this time, we must provide a special definition for C-style string, which is template specialization
1. Specialization of function template
The forms of specialization are as follows:
- The keyword tempalt is followed by a pair of empty angle brackets (< >)
- The function name is followed by the template name and a pair of angle brackets, which specify the template parameters of this specialization definition
- Function parameter table
- Function body
template<> int compare<const char *>(const char *const &v1,const char *const &v2) { return strcmp(v1,v2); }
1. Declaration template specialization
Like any function, function template specialization can be declared without definition.
template<> int compare<const char *>(const char *const &,const char *const &);
2. Function overloading and template specialization
If the empty template parameter table template < > is omitted from the specialization, the result is function overloading rather than template specialization
int compare(const char *const&,const char *const&); //The overloaded version of the function is declared instead of the template version
3. Specialized scope rules
Before calling this specialized version of the template, the specialized declaration must be in the scope
template<class T> int compare(const T&t1,const T& t2) { ... } int main() { int i=compare("hello","world"); ... } template<> int compare<const char *>(const char *const &s1,const char *const &s2) { ... }
There is an error in this program. This function will call the original template function that is not specialized
Specialization after a call to this template instance is an error
2. Specialization of class template
1. Definition of class specialization
template<> class Queue<const char*>{ public: void push(const char *); void pop();{real_queue.pop();} bool empty()const{return real_queue.empty();} std::string front(){return real_queue.front();} const std::string &front()const{return real_queue.front();} private: Queue<std::string>real_queue; };
A class template specialization should define the same interface as the template it specializes, otherwise users will be surprised when they try to use undefined members
2. Define members outside the class specialization
void Queue<const char *>::push(const char*val) { return real_queue.push(val); }
When a class specialization defines a member externally, the member cannot be preceded by the template < > tag
3. Specialized members rather than specialized classes
template<> void Queue<const char*>::push(const char *const &val) { ... } template<> void Queue<const char *>::pop() { ... }
Now, the class type queue < const char * > will be instantiated from the generic class template definition, with the exception of push and pop functions. When calling the push or pop function of the queue < const char * > object, the specialized version will be called; When any other member is called, it is converted from the class template to const Char * instantiates a generic version.
4. Partial specialization of class template
If the class template has more than one template parameter, we may want to specialize some template parameters instead of all. This can be achieved by using partial specialization of the class template:
template<class T1,class T2> class some_template{ //... }; //partial specialization template <class T1> class some_template<T1,int>{ //... }
Partial specialization using class templates
some_template<int,string>foo;//Using class templates some_template<string,int>bar;//Use partial specialization
1. The instantiation type of foo does not match the partial specialization type provided. Therefore, the type of foo must be instantiated from the general class template
2. Select some specialized templates to instantiate. When partial specialization is declared, the compiler will select the most specialized template definition for instantiation. When no partial specialization can be used, the general template definition will be used.
ps: function templates are not partially specialized. If a partially specialized function template is declared, the compiler will report an error