12.C++:模版进阶

目录

一、非类型模版参数

二、模版的特化

2.1、模版特化的概念

2.2、函数模版特化的具体操作

2.3、类模版的特化

2.3.1、全特化

2.3.2、偏特化(半特化)

三、模版的分离编译

3.1、什么是分离编译

3.2、模版的分离编译

四、模版的优缺点


一、非类型模版参数

前面我们一直用的类型模版,其实模版还有非类型模版,而且还可以给缺省值

比如,在定义一个静态数组的时候,你一开始给了10个空间,但是如果要存放1000个数据呢?但是如果你给了1000个空间,那么如果只有10个数据呢,那是不是就空间浪费了。所以,模版还给了非类型模版,解决了这个问题

cpp 复制代码
template<size_t N = 10>
struct a
{
    int arr[N];
} 

Note:(1)该做法只支持整型变量,对于浮点型,类类型和字符串时不行的。

(2)非类型的模版参数必须在编译时就确定。(比如:不能取决于用户的输入)

二、模版的特化

2.1、模版特化的概念

通常情况下,模版可以解决与类型无关的通用代码,但是对于一些特殊类型的操作可能会导致一些错误的结果,这时候,就需要对特殊的类型进行特化处理

2.2、函数模版特化的具体操作

(1)首先,你必须有一个基础的函数模版

(2)然后在 template后面接上一对空的 <>

(3)函数名后面再跟一对尖括号,尖括号里面放想要特化的类型

(4)函数的形参表:必须要和模版函数的基础参数类型完全相同

cpp 复制代码
template<class T>
void print(const T& val, const T& x)
{
	std::cout << val << x << std::endl;
}
//特殊处理double类型
template<>
void print<double>(const double& val, const double& x)
{
	std::cout << val + x<< std::endl;
}

Note:经过主包的实验,缺省值不影响,只要参数顺序,类型对得上就行。这里还要注意指针的const 修饰哦!

2.3、类模版的特化

类模版的特化对内部成员不要求一致。

cpp 复制代码
template<typename T>
class Printer {
public:
    void print() {
        std::cout << "General template" << std::endl;
    }
};
// 特化版本 - 当 T 为 int 时的特殊实现
template<>
class Printer<int> {
public:
    void print() {
        std::cout << "Specialized for int" << std::endl;
    }
};

2.3.1、全特化

将模版参数列表中的所有参数全部特化

2.3.2、偏特化(半特化)

任何针对模版参数进一步进行条件限制设计的特化版本,且不在要求空的 <>。

Note:只有偏特化不要求空的 <>

cpp 复制代码
template<typename T>
class Container {
public:
    void describe() {
        std::cout << "General container for type T" << std::endl;
    }
};
// 偏特化 - 当T是指针类型时的特殊实现
template<typename T>
class Container<T*> {  // 注意:尖括号里有 T*
public:
    void describe() {
        std::cout << "Specialized container for pointer types" << std::endl;
    }
};

三、模版的分离编译

3.1、什么是分离编译

一个程序右若干个源文件共同实现,每个源文件生成的目标文件链接起来形成一个单一的可执行文件的过程就是分离编译模式。

3.2、模版的分离编译

在学习模版的时候,有一条规则:不要把模版分离编译,如果非要这么干,也必须保证声明和定义在同一个文件下!现在,我们就来探讨一下为什么。

首先要回顾一下相关概念:

预处理:展开头文件,条件编译,宏替换,删除注释......(.h /.cpp -> .i)

编译:检查语法,生成汇编代码 (.i -> .s)

汇编:把汇编代码转换为二进制机器码 (.s -> .o)

链接:合并生成可执行程序,链接在其他文件定义的函数等 (.o -> .out)

那么,为什么模版不能分离定义?

因为模版没有实例化!编译器不知道实例化成什么类型!所以就没有实际代码出现。

3.3、解决办法

显示实例化

cpp 复制代码
template<typename T>
MyClass<T>::MyClass(T v) : value(v) {}

template<typename T>
void MyClass<T>::print() {
    std::cout << "Value: " << value << std::endl;
}

// 显式实例化你需要的类型
template class MyClass<int>;      // 实例化int版本
template class MyClass<double>;   // 实例化double版本

Note:不推荐!这样就丧失了泛型编程的意义

所以还是建议大家老老实实的不要分离编译,把它们放在同一个文件中。

四、模版的优缺点

优点:写出更灵活,更通用的泛型代码

缺点:报错不准,有时难以查错;

代码膨胀,让编译出的程序更大

相关推荐
threelab2 分钟前
Three.js 几何图形变换 | 三维可视化 / AI 提示词
开发语言·前端·javascript·人工智能·3d·着色器
无限进步_5 分钟前
Linux进程等待——wait、waitpid与僵尸进程
linux·运维·服务器·开发语言
野生技术架构师8 分钟前
Java 23 种设计模式:从踩坑到精通 —— 开篇及系列介绍
java·开发语言·设计模式
Wang ruoxi9 分钟前
Pygame 小游戏——数独
开发语言·python·pygame
人道领域15 分钟前
【LeetCode刷题日记】90.子集Ⅱ--- 归纳题解
java·开发语言·leetcode
随意起个昵称15 分钟前
线性dp-LIS题目5(导弹拦截,二分优化)
c++·算法·动态规划
ch.ju21 分钟前
Java Programming Chapter 4——Characteristics of inheritance
java·开发语言
复园电子22 分钟前
企业PDF批量盖章开发集成指南:API对接OA/LIMS系统,高并发落地实战
开发语言·python·pdf
光电笑映25 分钟前
进程间通信:深入 System V IPC:共享内存、消息队列与信号量
linux·运维·服务器·c++
SunnyDays101127 分钟前
如何使用 C# 自动调整 Excel 行高和列宽
开发语言·c#·excel