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

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

四、模版的优缺点

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

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

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

相关推荐
mengzhi啊19 分钟前
QEventLoop loop配合loop.exec();替代while(1)。电脑cpu占用为0,使用while(1)cpu占用率100%
c++·qt
HugoStudio_SWAN28 分钟前
洛谷 P1319 / P1320 压缩技术——同一枚硬币的正反面
c++·学习·程序人生·算法
wuyk55533 分钟前
Python 零基础入门第九章:用户输入与 While 循环
开发语言·python
兮动人37 分钟前
Python变量与常量
开发语言·python·机器学习·python变量与常量
风筝在晴天搁浅44 分钟前
解题代码清爽版
java·开发语言
Java后端的Ai之路1 小时前
21、Python - 命令模式
开发语言·人工智能·python·命令模式·外观模式
小小晓.1 小时前
C++单例模式万字详解:6种实现演进+线程安全彻底解决+CRTP终极模板
c++·单例模式
astronautyi1 小时前
Go 运行时内存分配与 GC 位图深度剖析
开发语言·后端·golang
techdashen1 小时前
Go 中如何处理错误
开发语言·后端·golang
孙克旭_1 小时前
JVM 入门详解:JVM、JRE、JDK 区别,JVM 基础结构梳理
java·开发语言·jvm