template_进阶_特化

目录

一. 内容

二. 函数模板_特化

1. typename

2. 非类型模板参数

3. 函数模板特化

1). 全特化

2). 偏特化

4. 类模板特化

1). 全特化

2). 偏特化


一. 内容

上次我们只是简单的谈了一下模板,我们只是可以简单的使用一下模板的泛型编程,这次我们看一模板的进阶,模板特化。

这次我们先看一下函数模板的特化,然后我们看类模板的特化,主要是一些我们之前不怎么使用的语法,下面我们来看一下。

二. 函数模板_特化

函数模板上一次我们就说过了,但是我们还是在看一下,由普通的函数模板引到函数模板的特化。

我们现在想要实现对一个数组的打印 print 函数,那么我们怎么实现?

1. typename

我们可以给 print 函数传一个 vector 的对象,然后我们使用 vector 的迭代器来打印~

void print(const vector<int>& v)
{
    std::vector<int>::const_iterator it = v.begin();
    while (it != v.end())
    {
        cout << *it << " ";
        ++it;
    }
}

那么我们现在要是还想要实习一个 string 的呢?

我们可以使用模板,我们将我们的 print 的参数当作一模板,我们下面试一下。

template<class Container>
void print(const Container& v)
{
    Container::const_iterator it = v.begin();
    while (it != v.end())
    {
        cout << *it << " ";
        ++it;
    }
}

那么我们就可以这样,我们可以将一个类型传过去,然后用该类型的 const_iterator 来进行遍历。

但是实际上这里是编译不过去的,我们看一下报错信息。

为什么会这样呢?

我们既然传过去的是一个类型,那么我们想下面这样取的话,我们可能会取到什么呢?我们可能取到的一个 static 的变量,我们还可能取到的是一个我们的类内的一个类,所以我既然可以取到是 static 的变量那么我们的语法就是错误的,由于编译器它也并不知道我们到底能取到什么,所以就直接报错了,那么我们怎么解决呢?

我们在前面加 typename 这个的意思是告诉编译器说这个是个类型,所以我们就可以编译通过了,那么我们现在加上去看一下是否可以成功。

template<class Container>
void print(const Container& v)
{
    typename Container::const_iterator it = v.begin();
    while (it != v.end())
    {
        cout << *it << " ";
        ++it;
    }
}

加上去之后就可以了,这里我们就不把测试的代码放出来了。

2. 非类型模板参数

我们现在想要实现一个静态的数组,并且我们的这个数组还是一个对象,那么我们该怎么实现呢?

我们由几种方法,其中一种就是 define 定义一个常量,然后我们将该常量传入到我们想要的数组中。

#define N 10

template<class T>
class Array
{
public:
private:
    T _a[N];
};

但是这个我们每一次定义的都是 10 个大小,我们要是想给大一点,我们就需要把所有的 Array 的对象的数组都给大,那怎么办呢?

我们下面的这个解决方法就是特意解决这种问题的,非类型模板参数。

我们可以在模板里面给一个整型的参数,我们就可以指定的传入这个参数。

template<class T, size_t N>
class Array
{
public:
private:
    T _a[N];
};

void test()
{
    Array<int, 10> a;
}

这个就是我们的非类型模板参数,实际上我们的非类型模板参数就是解决类型的问题的,而且我们的非类型模板参数的限制比较多,我们下面可以看一下。

非类型模板参数只能是整型家族的。

template<class T, double N>
class Array
{
public:
private:
    T _a[N];
};

如果是 double 那么就是直接报错了,但是这里的代码看不出来,可以自己取试一下

非类型模板参数是一个常数,所以我们不能修改。

template<class T, size_t N>
class Array
{
public:
    void fun()
    {
        N = 10;
    }
private:
    T _a[N];
};

void test()
{
    Array<int, 10> a;
    a.fun();
}

 我们调用的话就直接报错了,这里还是显示不出来但是可以自己取试一下。

3. 函数模板特化

1). 全特化

为什么前面说 typename 呢? 因为这个 typename 和 class 的一个区别。

下面我们来说特化

我们来看下面的一段代码,这段代码会输出什么呢?

template<class T1, class T2>
int Less(T1 x, T2 y)
{
    return x < y;
}


void test2()
{
    cout << Less(1, 2) << endl;
    cout << Less(1.1, 2) << endl;
    cout << Less(1, 2.2) << endl;
}

其实这个我们是没有太多要问题的,那么我们如果传入的是一个 int* 的类型呢?

template<class T1, class T2>
int Less(T1 x, T2 y)
{
    return x < y;
}


void test2()
{
    int x = 1, y = 2;
    cout << Less(&x, &y) << endl;
}

这个我们知道我们传入的是一个指针,我们肯定是以它的地址大小比较的,所以这时候我们就可以进行模板的特化。

template<class T1, class T2>
int Less(T1 x, T2 y)
{
    return x < y;
}

template<>
int Less<int*, int*>(int* x, int* y)
{
    return *x < *y;
}

这里先看代码,要是直接说的话怕是说不明白的,下面的那个就是模板特化的一个语法,所以我们不需要取纠结。

我们既可以特化指针,我们还可以特化其他的,我们知道函数调用就是调用最接近的函数。我们看一下其它的特化。

template<>
int Less<int, double>(int x, double y)
{
    return x < y;
}

void test2()
{
    cout << Less(1, 1.1) << endl;
}

我们上面讲的是特化里面的全特化,我们还有就是半特化。

2). 偏特化

偏特化也就是半特化顾名思义,就是只特化里面部分类型。

template<class T1>
int Less<T1, double>(T1 x, double y)
{
    return x < y;
}

就是这样我们只特化一半的类型。

上面只是我们的函数的特化,那么下面我们看一下类模板特化。

4. 类模板特化

1). 全特化

我们现在有一个 Date 类型的对象,我们现在想要对它进行模板的特化。

template<class T1, class T2>
class Date
{
public:
    Date()
    {
        cout << "Date(T1, T2)" << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};

我们现在想要对其进行特化一个 int, int 类型的

template<>
class Date<int,int>
{
public:
    Date()
    {
        cout << "Date(int, int)" << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};

我们在看一下 int, double 的

template<>
class Date<int, double>
{
public:
    Date()
    {
        cout << "Date(int, double)" << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};

上面这个就是全特化,我们特化就是语法,所以我们记住怎么样使用,下面我们看一下偏特化。

2). 偏特化

我们就是特化部分类型

template<class  T1>
class Date<T1, double>
{
public:
    Date()
    {
        cout << "Date(T1, double)" << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};

我们的特化实际上不是只能对参数进行修改,我们还可以对类型进行限制。

我们可以对类型进行限制为指针,也可以限制为引用。

template<class T1, class T2>
class Date<T1*, T2*>
{
public:
    Date()
    {
        cout << "Date(T1*, T2*)" << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};

我们上面这个是指针,我们还可以限制为是引用,所以我们的模板的偏特化,还可以是类型的限制。

上面就是我们今天的模板进阶~

模板还是需要多使用才能孰能生巧,所以还是希望可以多使用~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Naxx Crazy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值