因为C++模板中有很多概念,总是容易忘记,所以学习了之后,特地总结一下,方便下次复习。

  

  1、类模板和模板类的区别

    类模板是一个关于类的模板

         模板类是类模板实例化后的实体。

 

    2、特化是针对模板参数更进一步的条件限制所设计出来的特化版本。

       模板全特化和偏特化,全特化是把所有模板形参进行限制。 偏特化是把部分形参进行限制。

  模板特化和偏特化后,还是一个类模板。

 

 

//Grap 为形参
template<typename Grap>
class Calculate
{
public:
    int GetGirth(const Grap& grap);    //获取周长
};

template<typename Grap>
int Calculate<Grap>::GetGirth(const Grap& grap)
{
    int iGirth = 0;
    for (int i = 0; i < grap.GetEdgeCount(); ++i)
    {
        iGirth += grap.GetEdgeLength(i);
    }
    return iGirth;
}


class Circle
{
public:
    int iR;
};

//特化,其中 Circle为实参
template<>
class Calculate<Circle>
{
public:
    int GetGirth(const Circle& grap);    //获取周长
};

//template<>        注意:不需要写这一行
int Calculate<Circle>::GetGirth(const Circle& grap)
{
    return 2 * grap.iR * 3.14;
}
View Code

 

      3、模板实例化

   一个通过具体值替换模板参数,从模板产生普通类、函数或者或者成员函数的过程。

  PS 实例化和特化

  实例化:查找到最匹配的模板后,根据实参从模板创建出常规类或函数的过程。

  特例化:对模板中的部分或全部参数进行特化,定义新模板的过程。

 

   4、类模板和函数模板的区别

     a) 类模板没有自动类型推导的使用方式。

   b)类模板在模板参数列表中可以有默认参数,既可以缺省。

     c)对函数模板,只能全特化,不能偏特化。PS(成员函数可以偏特化)

 

  5、函数模板不能自动类型转换。

  void max(T a, T b);

  调用 max('a',42.6) 编译错误。

 

  6、函数重载可以完成代替函数偏特化

#pragma once

template<typename T1,typename T2>
void func(T1 t1, T2 t2)
{

}


#if 0
/*
不能偏特化
*/
    template<typename T2>
    void func<int,T2>(int t1, T2 t2)
    {

    }
#endif

//可以通过重载实现偏特化的效果

template<typename T2>
void func(int t1, T2 t2)
{

}
View Code

 

  7、类模板偏特化

#pragma once

template<typename T1,typename T2>
class D
{

};

template<typename T1>
class D<T1,int>
{

};

 

8、类模板的显式实例化,在未调用的时候就已经实例化了。

template<typename T>
class E
{

};

//类的显示实例化
template class E<int>;

9、函数模板的显式实例化

template<typename T>
void Fun(T t)
{

}
//函数的显式实例化
template void Fun<int>(int);

 

函数显示实例化可以使编译的时候只产生一个模板类,如果不是显示实例化,则在每个cpp对应的obj中生成一个弱函数,最后链接的时候选择第一个。

 

模板编译时会进行两阶段检测。

模板编译时,进行和类型参数无关的检测,如未定义的符号等。

模板实例化时,进行类型参数相关的检查。

 

使用this,若类模板的基类也是类模板,这时在类模板中不能之间通过名称调用从基类继承的成员,而应该通过this->或Base::

tmeplate<typename T>
class Base
{
public:
    void bar(){};
};

template<typename T>
class Derived:public Base<T>
{
public:
    void foo()
    {
          bar();      //error
          this->bar();    //ok
          Base<T>::bar();  //ok
    }
};

 

SFINAE(替换失败不是错误)

 

类内的模板函数不能是虚函数,普通函数可以是虚函数。

因为虚函数的通常实现是使用固定大小的虚函数表,每个虚函数有一个入口。然而,模板函数的实例数不是固定的,直到整个程序被编译一遍。