类模板和函数模板

函数模板:

函数模板全特化:所谓特化,是指相对普通模板的特化,是另外一个模板。但不是实例,只是模板

template <class T>                                      //普通函数模板,泛型
T mymax(const T t1, const T t2)
{
   return t1 < t2 ? t2 : t1;
}

template <>
const char* mymax(const char* t1,const char* t2)      //全特化的函数模板
{
   return (strcmp(t1,t2) < 0) ? t2 : t1;

}

template <>
const char* mymax<const char*>(const char* t1,const char* t2)      //全特化的函数模板
{
   return (strcmp(t1,t2) < 0) ? t2 : t1;

}

mymax后有没有<>,都可以,只是加上<>,表示是显式给定类型参数,如果没有<>则是要求编译器进行实参演绎;

实参演绎:实参演绎是一非常种灵活的机制,实参演绎的字面意思就是:通过实参的类型来推断函数模板的类型参数,举个简单的函数模板的例子:

template<typename T>
T& func1(T  &a,  T &b)
{  
     cout<<typeid(T).name()<<endl;
 }  

int a,b;func1(a,b);
也就是说,虽然我们没有为func指定T,编译器也可以通过a、b的类型来推断出T是什么,这里T被推断成了int。

模板特化:

类模板的部分特化本身也是模板。部分特化的定义看来像模板定义,这种定义以关键字template开头,接着是由尖括号(<>)括住的模板形参表。部分特化的模板形参表是对应的类模板定义形参表的子集。  

特化之后可以与普通的作用完全不同,甚至连成员函数也可以不相同

template<>class compare<char *> //特化(char*)
{
 public:
    bool IsEqual(char* t1, char* t2)
    {
        return strcmp(t1, t2) == 0;         //使用strcmp比较字符串
    }
};

template <class T>
class compare
{
 public:
 bool IsEqual(T t1, T t2)
 {
      return t1 == t2;
 }
};

int main()
{
 char str1[] = "Hello";
 char str2[] = "Hello";
 compare<int> c1;
 compare<char *> c2;   
 cout << c1.IsEqual(1, 1) << endl;        //比较两个int类型的参数
 cout << c2.IsEqual(str1, str2) << endl;   //比较两个char *类型的参数
 return 0;
}

注意:进行类模板的特化时,需要特化所有的成员变量及成员函数,所以全特化之后,可以像使用普通类一样进行类的成员函数定义,不需要template<class T> void Sample<T> ::add(){},只需要void Sample<int>::add(){}

函数模板的偏特化(x):没有函数模板偏特化这个概念,可以用函数模板的重载实现偏特化带来的效果

函数模板的重载:

作用:提供了修改函数模板(类成员函数模板)的途径,允许同名的函数模板,可以具有不同的返回值类型和形参类型。编译器根据实际调用的函数参数进行相应的函数模板的选择调用和具现。

跟普通函数的重载不同的是,返回值也要考虑其中:

template <class T>
bool mymax(const T t1, const T t2)
{
   return t1 < t2 ? t2 : t1;
}

template <class T>
T mymax(const T t1, const T t2)
{
   return t1 < t2 ? t2 : t1;
}
//问题又来了,大家都知道函数重载是不关心返回值的,而只关心参数个数以及类型是否不一致,不一致就是重载,但是对于模板函数而言,这个规矩不再成立,因为任何与模板相关的东西都只是个架子放在那里而已,只要它符合语法规则就可以了,这些架子只是在有人要调用它们时才会发挥效力,也就是说,在编译的时候会为你搜寻合适的模板函数或者类,只要能找到就ok了,而且还要求是只找到一个,要是找到多个也不行,呵呵。




#include <stdio.h>
template <class T>
void func(T a){
printf("使用func(T a)模板
");
}
//函数模板的重载
template<class T1, class T2>
int func(T1 t1, T2 t2){
printf("使用func(T1 t1, T2 t2)模板
");
return 1;
}
int main(void){
func(30, 60);  //使用重载的函数模板
func(19);
return 0;
}

函数模板重载用于实现函数的偏特化中:

template <typename T1, typename T2>
bool mymax(T1 t1, T2 t2)
{
   return t1 < t2 ? t2 : t1;
}

template <typename T1>
bool mymax(T1 t1, int t2)
{
   return t1 < t2 ? t2 : t1;
}

使用函数模板的重载实现函数偏特化

模板的实例化:所谓实例化,就是把类模板生成具体的类,把函数模板生成具体的函数

隐式实例化:在生成类的对象之前,不会隐式生成类实例

mymax<int,int> my;//此时就是implicit instance

类模板的成员函数本身也是函数模板,所以类模板实例化之后,本身的成员函数并没有实例化,它也是按需实例化,一旦调用了此成员函数,才实例化。

与普通的函数模板不同的是,在实例化类模板成员函数时,成员函数的形参由调用该函数的对象的类型确定,

例如,当调用 Queue<int>  类型对象的 push 成员时,实例化的 push 函数为 

     void Queue<int>::push(const int &val) 

显示实例化:template class Store<double> //显示生成double类型的store类

                 template  void  func<int>(int x)//显示生成一个fuc函数

参数推导:只有函数模板,才可以忽略<int>这个形式:(在实参可以推导的情况下)

func<int>(4);

func(4);//都生成模板,有的可以省略<int>

对于函数模板的全特化,也可以省略<int>这步

template<>

        bool operator()<double>(const double &a,const double &b)const 

        {           

            if(N > 0) return a - b > 1E-7;

            if(N < 0) return a - b < -1E-7;

           return (a - b >-1E-7) && (a - b<1E-7) ;

      }

   template<>   bool operator()(const double &a,const double &b)const {}//也是可以的

                      

 利用类模板的偏特化:

特化为另外一个类模板:
// specialize for vector<T>
template<class T>
class Compare<vector<T> >
{
public:
    static bool IsEqual(const vector<T>& lh, const vector<T>& rh)
    {
        if(lh.size() != rh.size()) return false;
        else
        {
            for(int i = 0; i < lh.size(); ++i)
            {
                if(lh[i] != rh[i]) return false;
            }
        }
        return true;
    }
};

template<typename T>
void swap(T& v1, T& v2) // #1
{
T t = v1;
v1 = v2;
v2 = t;
}

template<typename T,class A>
void swap(vector<T,A>& v1, vector<T,A>& v2) // #2
{
v1.swap(v2);
}

这个是函数模板的重载。最优化的优于次特化的,即模板参数最精确匹配的具有最高的优先权,所以vector调用时,调用的是第二个函数模板(因为最匹配).

 类模板的成员函数的特化:

例1:类模板的成员函数的特化

此处特化的是类

template <class T>
class Sample
{
public:
    void print() {printf("
print template");}
};

void Sample<int>::print() {printf("
print int");};

// 调用
int _tmain(int argc, _TCHAR* argv[])
{
    Sample<int> a;
    a.print();

    Sample<double> b;
    b.print();

    return 0;
}

类的成员函数模板

例2:类的成员模板函数的特化

此处,仅特化函数

class Sample2
{
public:
    template <class T>
    void print()
    {printf("
Sample2 print template");}
};

template <>
void Sample2::print<int>()
{printf("
Sample2 print int");}

// 调用
int _tmain(int argc, _TCHAR* argv[])
{
    Sample2 sam2;
    sam2.print<double>();
    sam2.print<int>();
    return 0;
}

// 输出
/*
Sample2 print template
Sample2 print int
*/

特别:类模板的成员函数模板不能特化,只能重载

原文地址:https://www.cnblogs.com/kkshaq/p/4515603.html