c++---非类型的类模板参数、类模板的特化、模板的分离编译

一. 非类型的类模板函数

在类的模板参数列表中,不一定是都是类型,或者适配器,也可以是一个数。

//一般都使用int,用作规定大小
template <class T,size_t MAXSIZE>

具体使用:

template <class int, size_t MAX_SIZE = 10>
class SeqList
{
public:
    SeqList();
protected:
    T _array[MAX_SIZE];
    int _size;
};

int main()
{   
    SeqList<int,20> s;
    SeqList<int> s1;  //使用缺省参数
}

   就像上面的代码,模板参数有两个,一个是顺序表中存储数据的类型,另一个就是非类型的类模板参数,用于指定当前顺序表所能存储最大数据的个数。

除了模板类可以有非类型的模板参数,模板函数也是可以有非类型模板参数。

template <class T ,int value = 20>
T add(const T& x)
{
    return x + value;
}
int main()
{
    cout<<add<int>(2)<<endl;
    cout<<add<int,30>(2)<<endl;
    return 0;
}

   像上面的代码,非类型模板参数可以带缺省值,可以让value为一个缺省值,如果不传第二个参数就默认为20,所以就有上面两种写法。我们若是不想使用默认值,就可以通过自己传参的方式来改变这个值。


浮点数和类对象是不允许作为非类型模板参数的。

二. 类模板的特化

   什么是特化呢?
   特化就是在写好的模板类中,可能会有单独的某种类型不能使用模板类中的定义,需要自己定义。
   就像是之前自己实现的vector模板类。在其中的拷贝构造,复制拷贝等操作,本来是可以使用memmove直接移动,可是考虑到string的深浅拷贝问题。我们就只能将所有元素一个元素一个元素赋值。就会导致效率降低,但是其他类型并没有这种问题,所以我们应该让string单独出来自己实现自己的vector类。就有了这里的特化。

全特化

一般格式就是这个样子:注意在特化的类上面应该加着templlate<>,并且特化后的类的类型应该是加上类型后的。T1。

#include <iostream>
#include <string>
using namespace std;
template<class T>
class T1
{
public:
    T1();
    ~T1();
protected:
    T t;
};
template<>
class T1<string>
{
public:
    T1();
    ~T1();
protected:
    string t;
    string t1;
};

偏特化(局部特化)

   特化不仅有全特化,还有偏特化。全特化是指对每一个参数都有确定的特化类型,特化后的类的参数都是确定的。偏特化是指对某个或某几个参数进行限制。
这是一种偏特化的例子,将一个参数确定,另一个不确定:

#include <iostream>
#include <string>
using namespace std;
template<class T1,class T2>
class T
{
public:
    T()
    {
        cout << "<T1,T2>" << endl;
    }
protected:
    T1 t;
};

template<class T2>
class T<int,T2>
{
public:
    T()
    {
        cout << "<int ,T2>" << endl;
    }
protected:
    int t1;
    T2 t2;
};

int main()
{
    T<int,string> t1;
    T<string, int> t2;
    return 0;
}

这里写图片描述
还有偏特化是将参数特化为指针类型与引用类型。

#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
template<class T1,class T2>
class T
{
public:
    T()
    {
        cout << "<T1,T2>" << endl;
    }
protected:
    T1 t;
};

template<class T2>
class T<T1*,T2*>
{
public:
    T()
    {
        cout << "<T1* ,T2*>" << endl;
    }
protected:
    int t1;
    T2 t2;
};

int main()
{
    T<int,string> t1;
    T<string*, int*> t2;
    T<string*, int> t2;
    system("pause");
    return 0;
}

这里写图片描述

三. 模板的分离编译

在之前写代码的正确格式应该是
这里写图片描述
   但是如果写了模板类,我们就不能使用这种格式来写了,因为会出现链接错误。为什么呢?之前说过,模板类与模板函数若是没有实例化是不产生实际代码的,所以在代码链接过程中,实例化是在main.cpp中,会找不到函数的定义。
   所以我们在写模板类模板函数时一般都要声明与定义放在一起。

总结:

模板的优点:

  1. 模板复用了代码,节省资源,更快的迭代开发,C++标准模板库产生
  2. 增强了代码的灵活性

缺点:

  1. 让代码变得凌乱复杂,不易维护,编译代码时间变长
  2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误。

猜你喜欢

转载自blog.csdn.net/weixin_40331034/article/details/80342640