C++ 模板2
创始人
2025-06-01 11:40:20
0

文章目录

  • 一、非类型模板参数
  • 二、模板特化
  • 三、模板分离编译的问题

一、非类型模板参数

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

  • 类型形参:用 class 和 typename 定义的参数
  • 非类型形参:模板参数中声明的一个变量,这个变量只能是整形家族的,并且只能当常量使用
#include using namespace std;// T 为类型参数,N 为非类型参数,只可以当常量使用
//模板参数的缺省规则和函数参数的缺省规则一样
template
class Array
{
public:size_t capaciyt() const{return N;}private:T arr[N];
};int main()
{Array a1;Array a2;// 输出 10 20cout << a1.capaciyt() << " " << a2.capaciyt() << endl;return 0;
}

二、模板特化

用模板可以实现通用的函数和类,但是有时想要对该模板中的某些类型进行特殊化处理,就需要使用模板特化,函数模板和类模板都可以进行特化,但通常函数模板特化可以用函数重载替代

模板特化的语法:

1. 必须要先有一个基础的函数模板或类模板
2. 模板关键字 template 后跟 <>,<> 中写出未特化的类型,都特化了就不写如果是偏特化中的满足条件特化则需要使用 typename 关键字后跟偏特化的类型
3. 函数名或类名后跟 <>,<> 中指定需要特化的类型,未特化的类型也需要写出
4. 函数名或类名、函数形参表需要和原模板保持一致

模板特化的使用:

#include using namespace std;// 定义一个通用的小于的仿函数
template
struct Less
{bool operator()(const T& x, const T& y){return x < y;}
};// 对 int* 进行特化
template<>
struct Less
{bool operator()(const int* x, const int* y){return *x < *y;}
};int main()
{// 创建匿名对象调用 less 模板,输出 1cout << Less()(1, 2) << endl;// 如果还是调用 less 模板,便只能用地址比较,可能输出 0// 通过特化后,可以用指针指向的内容进行比较,输出 1int* p1 = new int(1);int* p2 = new int(2);cout << Less()(p1, p2) << endl;return 0;
}

模板特化分为 全特化偏特化(半特化)

  • 全特化:将模板参数列表中的所有参数都确定化
  • 偏特化:1. 对部分参数特化, 2. 对满足条件的类型特化
#include using namespace std;// 类模板
template
class demo
{
public:// 构造函数demo(){cout << "demo" << endl;}
};// 全特化
template<>
class demo
{
public:demo(){cout << "demo" << endl;}
};// 偏特化,对部分参数特化
template
class demo
{
public:demo(){cout << "demo" << endl;}
};// 偏特化,对满足条件的类型特化
// 当两个参数都是指针类型时的特化
template
struct demo
{
public:demo(){cout << "demo" << endl;}
};int main()
{// 调用模板,输出 demodemo d1;// 调用全特化,输出 demodemo d2;// 调用偏特化中的部分特化,输出 demodemod3;// 调用偏特化中的满足条件特化,输出 demodemod4;return 0;
}

三、模板分离编译的问题

通常在写项目时,都会将声明写在 .h 文件中,定义写在 .cpp 文件中,但是对于函数模板和类模板而言,如果将声明和定义分离,将会出现链接错误

// demo.h
#pragma once#include using namespace std;template
class demo
{
public:// 声明函数demo();
};// demo.cpp
#include "demo.h"// 定义函数
template
demo::demo()
{cout << "demo()" << endl;
}// test.cpp
#include "demo.h"int main()
{demo d;return 0;
}

编译时提示链接错误

  • 文件经过预处理后,.h 会被拷贝到包含的 .cpp 文件中
// demo.cpp
#pragma once#include using namespace std;template
class demo
{
public:// 声明函数demo();
};// 定义函数
template
demo::demo()
{cout << "demo()" << endl;
}// test.cpp
#pragma once#include using namespace std;template
class demo
{
public:// 声明函数demo();
};int main()
{demo d;return 0;
}
  • 编译时 .cpp 文件都会单独编译

编译完成后,由于 test.cpp 文件中有 demo 的声明,因此 demo d 可以转化为 call demo()(地址),不过在 demo.cpp 文件中虽然有 demo 的声明和定义,但是 demo 无法知道要实例化什么类型的 demo,因此也就不会实例化,所以链接时,test.cpp 中就无法找到 demo,也就导致了链接错误

解决方法:

  • 显示实例化,这个方法不好用
// 在 demo.cpp 文件中,像如下声明需要使用的类型
template
demo::demo();
  • 声明和定义都放在 .h 文件中或者 .hpp 这里的后缀是用来暗示这个文件是模板,推荐使用这种
// 只写 demo.h 文件,不需要 demo.cpp 文件
#pragma once#include using namespace std;template
class demo
{
public:// 声明函数demo();
};// 定义函数
template
demo::demo()
{cout << "demo()" << endl;
}

模板优点:模板增加了代码的复用性
模板缺点:模板出现编译错误时,错误信息非常凌乱,不容易查找到错误

上一篇:zigbee 外部中断

下一篇:Flink快速了解

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...