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:不推荐!这样就丧失了泛型编程的意义

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

四、模版的优缺点

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

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

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

相关推荐
会周易的程序员21 小时前
多模态AI 基于工业级编译技术的PLC数据结构解析与映射工具
数据结构·c++·人工智能·单例模式·信息可视化·架构
Davina_yu21 小时前
Windows 下升级 R 语言至最新版
开发语言·windows·r语言
阿珊和她的猫21 小时前
IIFE:JavaScript 中的立即调用函数表达式
开发语言·javascript·状态模式
listhi52021 小时前
卷积码编码和维特比译码的MATLAB仿真程序
开发语言·matlab
yuan199971 天前
基于主成分分析(PCA)的故障诊断MATLAB仿真
开发语言·matlab
J_liaty1 天前
Java版本演进:从JDK 8到JDK 21的特性革命与对比分析
java·开发语言·jdk
翔云 OCR API1 天前
发票查验接口详细接收参数说明-C#语言集成完整示例-API高效财税管理方案
开发语言·c#
Chasing Aurora1 天前
Python后端开发之旅(三)
开发语言·python·langchain·protobuf
kong79069281 天前
Java基础-Lambda表达式、Java链式编程
java·开发语言·lambda表达式
lixzest1 天前
C++上位机软件开发入门深度学习
开发语言·c++·深度学习