C++之模版详解(进阶)

C++之模版详解(进阶)

目录

1. 非类型模板参数

2. 类模板的特化

2.1 函数模板特化

2.2 类模版特化

3. 模板的分离编译


1. 非类型模板参数

模版参数有两种,一种叫类型模版参数,一种叫做非类型模版参数。今天我们来讲讲非类型模版参数。

template <int N> 中的 int N 就是典型的非类型模板参数。这里的 int 是参数的类型,而 N 是参数名,它接收的是一个具体的常量值,而非像普通类型模板参数(如 template <typename T>)那样接收一个 “类型”。

两者核心区别就是:

  • 类型模板参数:传递 “类型”(如 T = int
  • 非类型模板参数:传递 “常量值”(如 N = 10

简单来说就是类型模版参数是改变类型,非类型模版参数改变的是类型后面的数。

注意:1. 浮点数、类对象以及字符串是不允许作为非类型模板参数的。2. 非类型的模板参数必须在编译期就能确认结果。

// 模板参数 <int N> 就是非类型参数(传递的是“值”) template <int N> // N 是一个编译期已知的整数 class FixedArray { private: int arr[N]; // 用 N 作为数组长度(编译时就确定了) public: // 打印数组长度 void printSize() { std::cout << "数组长度是:" << N << std::endl; } }; int main() { // 实例化时指定具体的“值”(非类型参数) FixedArray<3> arr3; // N=3,创建一个长度为3的数组 FixedArray<5> arr5; // N=5,创建一个长度为5的数组 arr3.printSize(); // 输出:数组长度是:3 arr5.printSize(); // 输出:数组长度是:5 return 0; }

2. 类模板的特化

2.1 函数模板特化

模板的特化(Template Specialization)是 C++ 中为模板提供 “特殊处理” 的机制。简单说就是:当模板的参数满足某种特定条件时,我们可以为它定义一套专门的实现,而不使用通用模板的代码

比如说下面这个代码,第一个Print就是普通的模版,第二个Print就是特化的模版。我们要在函数的名字后面加上<char>说明我们要特殊处理的是char类型的。由于计算机是从上往下编译的,所以当它在mian函数里面遇到Print,同时里面是char类型的时候,它会自动匹配第二个,然后打印出对应的ASCII码。

#include <iostream> // 通用模板(适用于大多数类型) template <typename T> void Print(T value) { std::cout << "通用模板:" << value << std::endl; } // 对 char 类型的特化版本 template <> // 特化标记:空参数列表,表示“针对特定类型” void Print<char>(char value) { // 明确指定特化的类型:char std::cout << "char 特化:字符 '" << value << "' 的 ASCII 码是 " << (int)value << std::endl; } int main() { Print(123); // 匹配通用模板,输出:通用模板:123 Print('A'); // 匹配 char 特化版本,输出:char 特化:字符 'A' 的 ASCII 码是 65 return 0; }

2.2 类模版特化

下面这个就是类模版特化中的全特化,简单来说就是给类的每一个参数都传递模版参数,就叫做全特化。

PS:如果只给一个类的部分参数传递模版参数那就是偏特化。

#include <iostream> #include <string> // 通用类模板:处理任意类型的数据 template <typename T> class DataProcessor { public: void process(T data) { std::cout << "通用处理:" << data << "(类型未知,按默认方式处理)" << std::endl; } }; // 全特化:专门处理 int 类型 template <> // 全特化标记(空参数列表) class DataProcessor<int> { // 明确指定特化的类型是 int public: void process(int data) { std::cout << "int 专用处理:" << data << "(整数翻倍后为 " << data * 2 << ")" << std::endl; } }; // 全特化:专门处理 string 类型 template <> class DataProcessor<std::string> { // 明确指定特化的类型是 string public: void process(std::string data) { std::cout << "string 专用处理:" << data << "(字符串长度为 " << data.size() << ")" << std::endl; } }; int main() { // 测试通用模板(处理 double 类型,没有特化版本) DataProcessor<double> dProc; dProc.process(3.14); // 用通用模板处理 // 测试 int 特化版本 DataProcessor<int> iProc; iProc.process(10); // 用 int 专用处理 // 测试 string 特化版本 DataProcessor<std::string> sProc; sProc.process("hello"); // 用 string 专用处理 return 0; }

3. 模板的分离编译

一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链 接起来形成单一的可执行文件的过程称为分离编译模式,比如说我写的那个boost搜索引擎项目就是分离编译模式。

这个就相当于写了一个通用的类,然后我们想用时对他进行调用。

Read more

Qiuner赠书活动:算法图解、C++ Primer Plus、大话数据结构、Java项目全程开发实录、算法导论、深度学习、第一视角带你构建大模型GPT

Qiuner赠书活动:算法图解、C++ Primer Plus、大话数据结构、Java项目全程开发实录、算法导论、深度学习、第一视角带你构建大模型GPT

* 人年轻时常觉空虚,总想找点什么填满自己。买书,是我曾经的一种方式。但买得多,看得少。最近想着,这些书放着也是放着,不如抽几本送给粉丝,包邮寄出。 * 抽奖方式为点赞收藏评论:我要抽奖,即可。 💥 Qiuner ‖ Bug Free Life交流群火热招募中! ① 🎁 进群即送:ZEEKLOG评论防封脚本 + 真·活跃粉丝,助你快速提升文章热度! ② 📘 独家福利:免费赠送写作秘籍一份,教你玩转ZEEKLOG,揭秘大佬涨粉的秘密! ③ 🏆 大佬云集:热榜 Top10 的常客、数不清的万粉大佬都在群里,畅聊写作技巧、上榜经验、涨粉秘籍! ④ 💼 专属资源:合作推广、推文活动一应俱全,为你打开副业变现新途径! 👉 有兴趣的加文末联系方式,备注你的ZEEKLOG昵称,立刻拉你进群! 🔍 或直接搜索:Qiuner520,备注“写作”,即可入群交流~ 🧠 一起互帮互助,共同进步,让你的ZEEKLOG之路不再孤单! * 除了本文在评论区所赠书外,

By Ne0inhk
计算机基础知识总结(八股文总结----计算机网络、操作系统、数据库、c++、数据结构与算法)

计算机基础知识总结(八股文总结----计算机网络、操作系统、数据库、c++、数据结构与算法)

一、操作系统 0.内存管理 01.什么是虚拟内存?为什么需要虚拟内存? 虚拟内存为程序提供比实际物理内存更大的内存空间,同时提高内存管理的灵活性和系统的多任务处理能力。虚拟地址空间就是进程所能看到的内存空间,这段空间是连续的、独立的,实际地址空间则是内存上的空间,这段是所有进程共享的、有限的空间。虚拟内存就是把实际地址空间映射到虚拟地址空间的技术,这样就实现了内存隔离、内存扩展、物理内存管理、页面交换等技术。内存隔离就是每个进程都有自己的虚拟地址空间,因此一个进程无法访问另一个进程的内存。内存扩展就是虚拟内存让每个进程拥有比实际大的内存空间地址,可以处理更多的数据、更大的进程。物理内存管理,内存空间不足时把不常用的数据转移到硬盘上,释放内存,以助于更多进程使用。页面交换,进程可能会造成外部内存碎片,可能会导致内存空间不足,这时把不常用的数据交换到硬盘上,再交换回来,就能消除内存碎片,之前技术是内存分段,现在都是内存分页,一页或几页的内存交换就能解决内存不足的问题,而且效率高,内存分段的大数据在硬盘上读取速度慢。 02.什么是内存分段和分页?作用是什么? 内存分段是将一个程序

By Ne0inhk
【C/C++刷题集】string类(一)

【C/C++刷题集】string类(一)

🫧个人主页:小年糕是糕手 💫个人专栏:《C++》《Linux》《数据结构》《C语言》 🎨你不能左右天气,但你可以改变心情;你不能改变过去,但你可以决定未来! 目录 一、字符串最后一个单词的长度 二、验证回文串 三、字符串中的第一个唯一字符 四、反转字符串 一、字符串最后一个单词的长度 字符串最后一个单词的长度 这里我们看题目有一个注意点就是我们平常使用cin输入时遇到空格会停下来,在例子中我们可以看到他有A B C D,如果我们使用cin在遇到第一个A之后就会报错,所以这里我们要用到另一种输入方式:getline 他并不是一个成员函数,而是输入流的全局函数 getline(istream&, string&)(定义在 <string> 头文件中),作用是从输入流中读取一整行内容,存入 string 对象。 // 基础用法(读整行) getline(

By Ne0inhk
千面之法: 释放 C++ 多态的灵活威力

千面之法: 释放 C++ 多态的灵活威力

目录 1:多态的概念 1.1:概念 2.多态的定义与实现 2.1:多态的构成条件 2.2:虚函数 2.3:虚函数的重写 2.3.1:虚函数重写的两个例外 2.3.1.1:协变(基类与派生类函数的返回值不同,基类虚函数返回基类对象的指针或引用,派生类虚函数返回派生类对象的指针或引用时) 2.3.1.2:析构函数的重写 2.4:C++11 override和final 2.4.1:final关键字 2.4.2:override关键字 2.5:重载、

By Ne0inhk