C++模板扩展

本文介绍了C++中的模板编程,包括非类型模板参数的概念,以及如何使用类型模板参数和非类型模板参数。重点讨论了模板的特化,包括全特化和偏特化在函数和类模板中的应用,以及一个关于`Less`模板和`Data`类模板的实例。
摘要由CSDN通过智能技术生成

目录

1.非类型模板参数

2.模板的特化


1.非类型模板参数

        我们知道,模板一般是不指定类型的,具体是什么类型由其他部分的代码的决定。

        模板参数分为类型模板参数和非类型模板参数。

        类型形参即:出现在模板参数列表中,跟在class或者typename之后的参数类型名称。
        非类型形参:就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。

        

// 定义一个模板类型的静态数组
 template<class T, size_t N = 10>
 class array
 {
 public:
 T& operator[](size_t index){return _array[index];}
 const T& operator[](size_t index)const{return _array[index];}
 
 size_t size()const{return _size;}
 bool empty()const{return 0 == _size;}
 
 private:
 T _array[N];
 size_t _size;
 };

        浮点数、类对象以及字符串是不允许作为非类型模板参数的。C++20目前似乎支持。

2.模板的特化

        特化即特殊处理的意思。

        先来看一个例子:

// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{
 return left < right;
}
int main()
{
 cout << Less(1, 2) << endl; // 可以比较,结果正确
 Date d1(2022, 7, 7);
 Date d2(2022, 7, 8);
 cout << Less(d1, d2) << endl; // 可以比较,结果正确
 Date* p1 = &d1;
 Date* p2 = &d2;
 cout << Less(p1, p2) << endl; // 可以比较,结果错误
 return 0;
}

         错误的原因就是因为这里比较的是地址的大小。要想避免这种情况发生,对模板特化。

// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{
 return left < right;
}
// 对Less函数模板进行特化
template<>
bool Less<Date*>(Date* left, Date* right)
{
 return *left < *right;
}
int main()
{
 cout << Less(1, 2) << endl;
 Date d1(2022, 7, 7);
 Date d2(2022, 7, 8);
 cout << Less(d1, d2) << endl;
 Date* p1 = &d1;
 Date* p2 = &d2;
 cout << Less(p1, p2) << endl; // 调用特化之后的版本,而不走模板生成了
 return 0;
}

        但一般都是直接给出这个函数。

bool Less(Date* left, Date* right)
{
 return *left < *right;
}

        上面是函数模板特化的情况。

        来看看类模板:

        第一种情况称为全特化,也就是把模板参数全部给出。 

        要注意,特化是在原有模板存在的基础上添加的东西,你可能觉得把模板参数全部给出不如直接写一个这样的类,但是特化!特化就是特殊处理模板不能直接实例化的这种类而做的处理。

         

template<class T1, class T2>
class Data
{
public:
 Data() {cout<<"Data<T1, T2>" <<endl;}
private:
 T1 _d1;
 T2 _d2;
};
template<>
class Data<int, char>
{
public:
 Data() {cout<<"Data<int, char>" <<endl;}
private:
 int _d1;
char _d2;
};
void TestVector()
{
 Data<int, int> d1;
 Data<int, char> d2;
}

        第二种情况称为偏特化,也有的说法叫半特化,这种用法挺有意思的。

        先来看看普通的偏特化:

 

template<class T1, class T2>
class Data
{
public:
 Data() {cout<<"Data<T1, T2>" <<endl;}
private:
 T1 _d1;
 T2 _d2;
};
// 将第二个参数特化为int
template <class T1>
class Data<T1, int>
{
public:
 Data() {cout<<"Data<T1, int>" <<endl;}
private:
 T1 _d1;
 int _d2;
}; 

        这种情况大家都容易想到,来看看下面这种,挺有意思的

template<class T1, class T2>
class Data
{
public:
 Data() {cout<<"Data<T1, T2>" <<endl;}
private:
 T1 _d1;
 T2 _d2;
};
//两个参数偏特化为指针类型
template <typename T1, typename T2>
class Data <T1*, T2*>
{ 
public:
 Data() {cout<<"Data<T1*, T2*>" <<endl;}
 
private:
 T1 _d1;
 T2 _d2;
};

比如:

#include<vector>
#include <algorithm>
template<class T>
struct Less
{
 bool operator()(const T& x, const T& y) const
 {
 return x < y;
 }
};
int main()
{
 Date d1(2022, 7, 7);
 Date d2(2022, 7, 6);
 Date d3(2022, 7, 8);
 vector<Date> v1;
 v1.push_back(d1);
 v1.push_back(d2);
 v1.push_back(d3);
 // 可以直接排序,结果是日期升序
 sort(v1.begin(), v1.end(), Less<Date>());
 vector<Date*> v2;
 v2.push_back(&d1);
 v2.push_back(&d2);
 v2.push_back(&d3);
 
 // 可以直接排序,结果错误日期还不是升序,而v2中放的地址是升序
 // 此处需要在排序过程中,让sort比较v2中存放地址指向的日期对象
 // 但是走Less模板,sort在排序时实际比较的是v2中指针的地址,因此无法达到预期
 sort(v2.begin(), v2.end(), Less<Date*>());
 return 0;
}

 全特化后:

// 对Less类模板按照指针方式特化
template<>
struct Less<Date*>
{
 bool operator()(Date* x, Date* y) const
 {
 return *x < *y;
 }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值