当前位置: 首页 > news >正文

模板进阶(仿函数,特化等介绍)

非类型模板参数

模板参数有类型形参和非类型形参;

类型形参:使用typename或者class修饰的参数类型名称

非类型形参:一个普通常量作为模板参数形参,不能为浮点数,字符类型以及类对象;

#include<iostream>
using namespace std;template<class T, size_t N = 64>
class test {private:T data = 10;
public:void print(){cout << data << endl << N << endl;}};int main()
{test<int> a;a.print();return 0;
}

上面的代码中,T就是典型的类型形参,N为非类型形参,这个N我们在类函数成员中可以直接使用

模板的特化

我们都知道,使用模板能够很方便的做出能够适应各种场景的函数,比如比较大小,加减法等函数:


template<class T>
bool Less(T a, T b)
{return a <  b;
}int main()
{cout << Less(1, 2) << endl;Date a(2022, 7, 8);Date b(2022, 7, 7);cout << Less(a, b)<< endl;return 0;
}

 

 

比如这样,就能够比较 int,double 之类的类型,但是有时候我们的类型可能无法满足我们的需求

 比如:

 我们需要比较的是Date类中的日期大小,但是我们传 Date* 类型进行比较时;

却发现比较的结果实际上是按照地址的大小来进行比较的。

对于这种情况,就需要我们的函数模板的特化出场了;

函数模板特化的步骤

1.有一个基础的函数模板

2.有一个template关键字,后面跟着一个空的<>

3.函数名后跟着一个<>,尖括号中指定需要特化的类型

4.函数形参表必须和模板函数的基础参数类型完全相同,否则会报错

比如上面的 Less 模板函数如何特化?

template<class T>
bool Less(T a, T b)
{return a <  b;
}template<>
bool Less<Date*>(Date* a, Date* b)
{return *a < *b;
}

 我们对比基础函数模板,我们发现,特化的函数模板不仅template后面跟着空的 <> ,而且函数名后还有一个 <> ,并且里面有特化的类型,且形参名都是相同的

这样我们就能够顺利比较 Date* 类型的参数了;

 

即然有函数的模板特化,那么就有类的模板特化

类的模板特化和函数的模板特化的规则类似。

类的模板特化

类的模板特化分为两种——全特化和偏特化;

我们先了解简单的全特化

全特化

template<class T1,class T2>
class Test {
public:Test(){cout << "Test(T1,T2)" << endl;}private:T1 a;T2 b;
};template<>
class Test<char, char> {
public:Test(){cout << "Test(char,char)" << endl;}
};int main()
{Test<int, int> t1;Test<char, char> t2;return 0;
}

全特化和函数特化一样,需要有基础的类模板,并且还得有其他一些条件才能实现特化;

若是创建的类对象和特化的类型一致,就会使用特化的类

偏特化

所谓偏特化就是指这个类并非全都是指定一个类型,而是有特化有没特化的。

template<class T1>
class Test<T1, int> {
public:Test(){cout << "Test(T1,int)" << endl;}
};

 就比如这个,我们指定特化第二个参数是 int 类型的,因此若是后面使用 int 类型当做第二个模板参数,就会使用这个类型;

int main()
{Test<int, int> t1;Test<char, char> t2;Test<char, int> t3;return 0;
}

 

而偏特化里面还有一个更特殊的——针对模板参数进一步条件限制设计出来的特化版本

这个和普通的偏特化不同,它的规则不同,我们先来看看实例;

template<class T1,class T2>
class Test<T1&, T2&> {
public:Test(){cout << "Test(T1&,T2&)" << endl;}
};

我们发现,它的template后不是跟着空 <>,其内部有正常的模板参数;

但是类名后面跟着不同指定特化的类型。

这就是进一步限制条件的特化版本

模板特化应用示例

比如我们使用一个仿函数用来比较函数时,我们有时单纯靠模板无法满足需求,就需要特化版本来满足需求;

template<class T>
class Less {bool operator()(const T&x,const T& y)const {return x < y;}

比如这个,我们比较普通的类型无所谓,但是若是比较的是 Date* 的类型时,就会比较地址大小导致出错,因此需要特化。

template<>
class Less<Date*>
{bool operator()(const Date* x, const Date* y){return *x < *y;}
};

模板分离编译

当我们写模板类的时候需要注意一个点——模板类不能分离编译。

什么是分离编译?就是指模板函数或者模板类的函数声明和定义分别在不同的文件

而模板函数和模板类的声明和定义在不同位置会导致出错。

这是因为编译器对于每个源文件都是独立编译的,若是分离编译则会导致源文件之间没有交互,导致对应的模板没有实例化,从而出错。

具体解决办法就是将声明定义放在一起,从而避免出错。

http://www.lryc.cn/news/36034.html

相关文章:

  • Beats:在 Docker 中同时部署 Metricbeat 和 Elasticsearch
  • 编码技巧——Redis Pipeline
  • ArcGIS制图技巧:制图入门与点、线、面状符号制作
  • Java基础 关于字典数据维护接口设计
  • 从零开始学架构——复杂度来源
  • 什么时候需要分表分库?
  • 冰刃杀毒工具使用实验(29)
  • 聊聊图像分割的DICE和IOU指标
  • 软件设计师教程(十)计算机系统知识-结构化开发
  • 链表OJ之 快慢指针法总结
  • C++STL详解(五)——list的介绍与使用
  • 进程和进程的调度
  • TypeScript 深度剖析:TypeScript 的理解?与 JavaScript 的区别?
  • 美颜SDK关键技术讲解——人脸识别与人脸美化
  • Linux下C/C++ 网络扫描(主机扫描技术)
  • 无法将“vue-cli-service”项识别为 cmdlet、函数、脚本文件或不是内部命令的原因和解决方案
  • 逆流程 场景下 处理状态机变化的方案
  • 【剧前爆米花--爪哇岛寻宝】Java实现无头单向非循环链表和无头双向链表与相关题目
  • 学习MvvmLight工具
  • 基于BiLSTM+CRF医学病例命名实体识别项目
  • 05 C语言数据类型
  • C++11:右值引用和移动语义
  • tcpdump网络抓包工具
  • MaxCompute SQL中的所有保留字与关键字如下
  • Kafka 压缩算法
  • 关于React Hook(18)
  • 计算机网络:BGP协议
  • 91. 解码方法 ——【Leetcode每日刷题】
  • 人体存在传感器成品方案,精准感知静止存在,实时智能化感控技术
  • mysql连接池的实现