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

C++模板进阶

一、非类型模板参数

模板参数分为:类型形参、非类型形参

类型形参:class与typename都是参数类型

非类型形参:用一个常量作为模板的一个参数,一般是整型常量

#include<iostream>
#include<array>
using namespace std;//class T为类型模板参数,用于适配各种类型
//size_ t N为非类型模板参数,只能为整型常量
template<class T,size_t N>//下面的size_t N虽然没有加const但默认为常量
class Array
{
public:
private:T _a[N];
};template<class T,size_t N=10>
//template<class T,double N=10>//会报错,类型非法
void func(const T& a)
{N = 20;//会报错必须为可操作得左值,说明N非类型模板参数为常量
}int main()
{//非类型模板参数可以对不同得对象开辟不同大小的空间Array<int,10> a1;Array<double,20> a2;int arr[15];array<float, 15> a3;//C++11中更新的容器,对标C语言中的静态数组//不提供初始化,但是有严格的越界检查,读写全面检查}

1.浮点数、类对象以及字符串是不允许作为非类型模板参数的

2.非类型模板参数必须在编译器就能确认

二、模板特化

模板对于一些特殊类型可能会产生一些错误的结果

就比如下面实现的比较大小的代码,对于Date类的特定对象可以实现对比功能,但是如果使用特定对象的指针进行比较,就会产生错误

因此需要使用模板进行特化,也就是在原来模板的基础上,对特殊类型进行特殊化处理

#include<iostream>
using namespace std;class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}friend ostream& operator<<(ostream& _cout, const Date& d){_cout << d._year << "-" << d._month << "-" << d._day;return _cout;}private:int _year;int _month;int _day;
};template<class T>
bool Less(T left, T right)
{return left < right;
}int main()
{cout << Less(1, 5) << endl;//1	可以比较,结果正确Date d1(2023, 5, 10);Date d2(2023, 5, 1);cout << Less(d1, d2) << endl;//0	可以比较,结果正确Date* p1 = &d1;Date* p2 = &d2;cout << Less(p1, p2) << endl;//1	可以比较,结果错误return 0;
}

可以参数Less函数一般都可以进行正常比较,但是以如上代码为例,进行自定义对象的对比正常,但是对于指向自定义类型对象的指针对比错误。因此需要特化

1.函数模板特化

函数模板的特化步骤:

1. 必须要先有一个基础的函数模板

2. 关键字template后面接一对空的尖括号<>

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

4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误

函数模板特化使用较少,因为可以直接给出特定的函数用于实现,也就是函数重载

#include<iostream>
using namespace std;class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}friend ostream& operator<<(ostream& _cout, const Date& d){_cout << d._year << "-" << d._month << "-" << d._day;return _cout;}private:int _year;int _month;int _day;
};template<class T>
bool Less(T left, T right)
{return left < right;
}//函数模板特化--对某些类型进行特殊化处理
template<>
bool Less<Date*>(Date* left, Date* right)//全特化
{return *left < *right;
}//实例化重载
bool Less(Date* left, Date* right)
{return *left < *right;
}void test_1()
{cout << "Less" << endl;cout << Less(1, 2) << endl;Date d1(2023, 5, 10);Date d2(2023, 5, 5);cout << Less(d1, d2) << endl;Date* p1 = &d1;Date* p2 = &d2;cout << Less(p1, p2) << endl;//调用特化之后的版本,不通过模板生成
}int main()
{test_1();return 0;
}

2.类模板特化

类模板特化分为全特化偏特化

全特化:即是将模板参数列表中所有的参数都确定化

偏特化:对模板参数进行限制的特化版本

全特化可以理解为所有参数都锁定的特化,偏特化可以理解为部分参数特化

 

#include<iostream>
using namespace std;//类模板
template<class T1,class T2>
class modle
{
public:modle(){cout << "modle<T1,T2>" << endl;}
private:T1 _m1;T2 _m2;
};//类模板全特化
template<>
class modle<int,char>
{
public:modle(){cout << "modle<T1,T2>" << endl;}
private:int _m1;char _m2;
};//偏特化
template<class T1>
class modle<T1, int>//将模板参数列表的一部分参数特化,将第二个参数转化为int
{
public:modle(){cout << "modle<T1,int>" << endl;}
private:T1 _m1;int _m2;
};//将两个参数偏特化为指针类型
template<typename T1,typename T2>
class modle<T1*, T2*>
{
public:modle(){cout << "modle<T1*,T2*>" << endl;}
private:T1 m1;T2 m2;
};//将两个参数偏特化为引用类型
template<typename T1, typename T2>
class modle<T1&, T2&>
{
public:modle(const T1& m1,const T2& m2):_m1(m1),_m2(m2){cout << "modle<T1&,T2&>" << endl;}
private:const T1& _m1;const T2& _m2;
};void test_2()
{modle<int, int> m1;//偏特化的部分参数特化版本modle<int,char> m2;//全特化modle<int*, int*> m3;//偏特化的指针版本modle<int&, int&> m4(1, 5);//偏特化的引用版本
}int main()
{test_2();return 0;
}

三、模板的分离编译

一个项目由若干个源文件共同实现,每个源文件会独立线性生成相应的预处理文件(.i),编译文件(.s),汇编文件(.o),最后再将所有目标文件链接,形成单一的可执行文件的过程为分离编译模式

 func.h

#pragma once
#include<iostream>
#include<array>
#include <vector>
using namespace std;template<class T>
T Add(const T& left, const T& right);template<class T>
T Add(const T& left, const T& right)
{return left + right;
}// 声明和定义放到一起,直接就可以实例化,编译时就有地址,不需要链接void func();
//模板不支持声明与定义不在同一个文件
//但是模板支持在一个文件内部,声明和定义分离#include"func.h"
template<class T>
T Add(const T& left, const T& right)
{return left + right;
}void func()
{cout << " void func()" << endl;
}//显式实例化,此时编译时就知道需要实例化一个double类型的Add函数
template
double Add<double>(const double& left, const double& right);
//但是这样对于其他类型需要不断得显示实例化,十分麻烦

工程只有再链接的时候才会寻找函数地址,但是函数模板只有在调用的时候才会产生实例化,因此再没有实例化的时候并没有地址,在链接时会产生报错

解决方法:

1.将声明和定义放在同一个文件内,一般都是统一放在头文件内

2.模板定义的位置显示实例化,对于多个不同类型调用十分麻烦,不建议使用

模板总结

优点缺点
模板复用代码,节省资源,使得代码简明高效模板会导致代码膨胀,对于不同的类型进行不同的实例化,会导致编译时间变长
增强的代码的灵活性出现模板编译错误时,错误信息凌乱,不易定位

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

相关文章:

  • 【人力资源管理】第4集 免费开源ERP: Odoo 16 Appraisal员工绩效评估 构建一体化企业人力资源管理
  • 「AI 孙燕姿」翻唱华语乐坛歌曲爆红全网,AI 翻唱将带来哪些影响?是否会有版权等问题?
  • 路径规划算法:基于灰狼优化的路径规划算法- 附代码
  • 推荐系统综述
  • SQLIST数据库编程
  • vue2中操作对象的方法
  • 左值引用、右值引用,std::move() 的汇编解释
  • LiangGaRy-学习笔记-Day11
  • 【异常解决】浏览器无法访问此网站ERR_UNSAFE_PORT/网页可能无法连接,或者它已永久性地移动到了新网址问题解决方案
  • Python函数的参数
  • 【Hive大数据】Hive分区表与分桶表使用详解
  • C#NPOI操作Excel详解
  • CSS中文字体 Unicode 编码表
  • 《微服务实战》 第四章 Spring Cloud Netflix 之 Eureka
  • 11. 深入理解并发编程-AQS与JMM
  • 深度解耦:使用Jetpack新技术Hilt实现依赖注入
  • C++ 构造函数-2
  • 网安笔记 08 key management
  • Linux socket
  • 14.构造器的排序分组.子查询
  • 【剑指 Offer】05,替换字符创中的空格;难度等级:简单。易错点:C++中 char 和 string 类型的转换
  • 图像分割入门教程
  • C++入门教程||C++ 信号处理||C++ 多线程
  • java计算矩形的面积和周长的方法
  • 一分钟掌握如何更换Jupyter Notebook的主题和字体
  • 如何系统全面的自学自动化测试?明确后我直接拿到了20K
  • 【搭建私有云盘】无公网IP,在外远程访问本地微力同步
  • Pytest自动化测试框架一些常见的插件
  • 【力扣】刷题+剑指offer第二版
  • QueryStorm Crack