C++-模板进阶

一、非类型模板参数

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

类型形参:出现在模板参数列表中,跟在class或typename后面的参数类型名称。

非类型形参:使用一个常量作为类(函数)模板的一个参数。

特点 :可以通过传参控制对象的属性,且只能传常量,不能传变量

限制 :非类型模板参数只能传整型,大部分时候只能适用于一些静态的结构,比如静态数组、静态栈、静态顺序表。

不能传变量的原因:编译期间需要进行实例化,而变量无法给出确定的值。

使用:C++11里有一个新容器array会使用,是一个静态数组(fixed-size sequence containers)。

二、模板的特化

模板特化:针对某些类型进行特殊化处理,模板特化分为函数模板特化和类模板特化。特化不能单独存在,必须得先有原模板。

2.1 函数模板特化

函数模板特化的步骤

cpp 复制代码
1.必须得有一个基础的函数模板。
2.特化的函数模板关键字template后面必须得接一对<>。
3.函数名后接一对<>,<>内指定需要特化的类型。
4.特化的函数形参表必须要跟模板函数的基础参数类型完全相同,不同的话编译器会报错。
cpp 复制代码
//原函数模板
template<class T>
T Add(const T& x, const T& y)
{
	return x + y;
}
//特化的函数
template<>
int Add<int>(const int& x, const int& y)
{
	return x + y;
}

特殊的栗子:const是修饰&的所以特化时int*需要放在const前面。

cpp 复制代码
//原函数模板
template<class T>
bool Less(const T& x, const T& y)
{
	return x < y;
}
//特化函数
template<>
bool Less<int*>(int* const& x, int* const& y)
{
	return *x < *y;
}

注:函数模板不建议特化,如果需要处理特定类型的函数可以直接给出。

2.2 类模板特化

类模板的特化分为全特化偏特化

1.全特化

全特化就是将每一个类模板参数进行确定。

cpp 复制代码
//原模板
template<class T1,class T2>
class Date
{
public:
	Date()
	{
		cout << "Date<T1,T2>" << endl;
	}
private:
	T1 _d1;
	T2 _d2;
};

//特化的类模板
template<>
class Date<int, char>
{
public:
	Date()
	{
		cout << "Date<int,char>" << endl;
	}
private:
	int _d1;
	char _d2;
};

2.偏特化

偏特化分为部分特化对模板参数的进一步限制

部分特化:

cpp 复制代码
//部分特化,对T1特化
template<class T2>
class Date<double,T2>
{
public:
	Date()
	{
		cout << "Date<double,T2>" << endl;
	}
private:
	int _d1;
	char _d2;
};
//对T2特化
template<class T1>
class Date<T1,double>
{
public:
	Date()
	{
		cout << "Date<T1,double>" << endl;
	}
private:
	int _d1;
	char _d2;
};

对模板参数的进一步限制:进一步的限制条件有*和&。

cpp 复制代码
//对模板参数的进一步限制

template<class T1,class T2>
class Date<T1*, T2*>
{
public:
	Date()
	{
		cout << "Date<T1*,T2*>" << endl;
	}
private:
	int _d1;
	char _d2;
};

template<class T1, class T2>
class Date<T1&, T2&>
{
public:
	Date()
	{
		cout << "Date<T1&,T2&>" << endl;
	}
private:
	int _d1;
	char _d2;
};

2.3 类模板特化的调用规则

实例化会按照最匹配原则进行调用。优先级是全特化>偏特化>原模板。

三、模板分离编译

分离编译:一个项目由若干个源文件共同实现,而每个源文件单独编译成目标文件,最后将所有的目标文件进行链接生成一个可执行文件,这个过程就是分离编译。

若模板的声明和定义在两个不同的文件中,例如声明在.h文件中,定义在.cpp文件中,在编译期间会报错。

模板不支持分离编译的原因:cpp文件中的模板函数在编译期间不会进行实例化,无法产生函数地址。

解决方法:

1.显示实例化(可用但不全面)

cpp 复制代码
#函数模板的显示实例化

template
类型 函数名<类型>(类型 形参,类型 形参);
cpp 复制代码
#Stack.h

#include<iostream>
using namespace std;

//声明
template<class T>
T Add(const T& x, const T& y);
cpp 复制代码
#Stack.cpp

#include"Stack.h"

//显示实例化
template
int Add<int>(const int& x, const int& y);

//定义
template<class T>
T Add(const T& x, const T& y)
{
	cout << "T Add(const T& x, const T& y)" << endl;
	return x + y;
}
cpp 复制代码
#类模板的显示实例化

template
返回值 类型::函数名(类型 形参)

template
返回值 类名<显示类型>::函数名(类型 形参)
cpp 复制代码
#Stack.h

#include<iostream>
using namespace std;

//声明
template<class T>
class Stack
{
public:
	void push(const T& val);
	void pop();
private:
	T* _a;
	int _capacity;
	int _size;
};
cpp 复制代码
#Stack.cpp

#include"Stack.h"

//显示实例化
template
void Stack<int>::push(const int& val);
template
void Stack<int>::pop();

//定义
template<class T>
void Stack<T>::push(const T& val)
{
	cout << "void push(const T& val)" << endl;
}
template<class T>
void Stack<T>::pop()
{
	cout << "void pop()" << endl;
}

2.只在同一个文件中对模板进行声明和定义分离,.hpp文件是大概率包含模板声明和定义的文件。

如果模板出现错误时错误可能或比较多和杂乱,看第一个错误会更好。

模板文件分离编译扩展阅读:

为什么C++编译器不能支持对模板的分离式编译-CSDN博客

相关推荐
接着奏乐接着舞1 小时前
java jvm知识点
java·开发语言·jvm
Shadow(⊙o⊙)1 小时前
qt中自定义槽函数 内部继承逻辑、GUI+CLI协同1.0
开发语言·前端·c++·qt
摇滚侠1 小时前
Java 基础面试题 真正的 offer 偏方 Java 基础 Java 高级
java·开发语言
雪度娃娃1 小时前
行为型设计模式——职责链模式
c++·设计模式·责任链模式
蚰蜒螟1 小时前
深入剖析 OpenJDK 17 解释器中的安全点(Safepoint)进入与退出机制
java·开发语言·安全
山岚的运维笔记1 小时前
Bash 专业人员笔记 -- 第 11 章:`true`、`false` 和 `:` 命令
linux·运维·服务器·开发语言·笔记·学习·bash
代钦塔拉1 小时前
第一篇:字符编码全解:从ASCII/GBK/Unicode到UTF-8
开发语言·qt
syagain_zsx1 小时前
Qt初识,快速上手
开发语言·qt
·心猿意码·1 小时前
OCCT源码解析(二):NCollection解析
数据结构·c++