欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 社会 > C++模板知识

C++模板知识

2025/5/3 18:20:36 来源:https://blog.csdn.net/nplplus/article/details/147669785  浏览:    关键词:C++模板知识

目录

引言 

一、非类型模板参数

二、类模板的特化 

(一)概念 

(二)函数模板特化 

(三)类模板特化 

1. 全特化 

2. 偏特化 

(四)类模板特化应用示例 

三、模板的分离编译 

(一)什么是分离编译 

(二)模板的分离编译 

(三)解决方法 

四、模板总结 

(一)优点 

(二)缺陷 


引言

在C++编程世界里,模板是一项极为强大且灵活的特性,它能让我们编写出通用、可复用的代码。今天,就让我们深入探究C++模板的几个关键方面:非类型模板参数、类模板的特化以及模板的分离编译。
 

一、非类型模板参数

模板参数分为类型形参与非类型形参。类型形参,我们常见于模板参数列表中,通常紧跟在 class 或者 typename 之后。而非类型模板参数则别具一格,它使用一个常量作为类(函数)模板的一个参数,在模板中可当作常量使用。
 
代码示例
 

cpp   
namespace bite {// 定义一个模板类型的静态数组template<class T, size_t N = 10>class array {public:T& operator[](size_t index) { return _array[index]; }const T& operator[](size_t index) const { return _array[index]; }size_t size() const { return _size; }bool empty() const { return 0 == _size; }private:T _array[N];size_t _size;};
}


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

二、类模板的特化
 

(一)概念
 

模板能实现与类型无关的代码,但遇到特殊类型时,可能会产生错误结果,这就需要对模板进行特化。特化即在原模板类基础上,针对特殊类型进行特殊化的实现方式。模板特化主要分为函数模板特化与类模板特化。
 

(二)函数模板特化
 

特化步骤
 
1. 首先得有一个基础的函数模板。
 
2. 使用关键字 template 后跟一对空的尖括号 <> 。
 
3. 函数名后紧跟一对尖括号,在尖括号中指定需要特化的类型。
 
4. 函数形参表必须要和模板函数的基础参数类型完全相同,否则不同编译器可能会报奇怪错误。


代码示例
 

cpp   
// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right) {return left < right;
}// 对Less函数模板进行特化
template<>
bool Less<Date*>(Date* left, Date* right) {return *left < *right;
}int main() {cout << Less(1, 2) << endl;Date d1(2022, 7, 7);Date d2(2022, 7, 8);cout << Less(d1, d2) << endl;Date* p1 = &d1;Date* p2 = &d2;cout << Less(p1, p2) << endl;  // 调用特化之后的版本,而不走模板生成了return 0;
}


 
一般情况下,如果函数模板遇到不能处理或者处理有误的类型,为实现简单,通常直接给出特化版本。函数模板不建议过度特化,因为直接编写普通函数实现简单明了,代码可读性高。
 

(三)类模板特化
 

1. 全特化
 

全特化即将模板参数列表中所有的参数都确定化。
 

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


 

2. 偏特化
 

偏特化是针对模板参数进一步进行条件限制设计的特化版本,主要有以下两种表现方式:
 
- 部分特化:将模板参数类表中的一部分参数特化。
 

cpp   
// 将第二个参数特化为int
template <class T1>
class Data<T1, int> {
public:Data() { cout << "Data<T1, int>" << endl; }
private:T1 _d1;int _d2;
};


 
 
- 参数更进一步的限制:不仅特化部分参数,还针对模板参数做更进一步的条件限制。
 

cpp   
// 两个参数偏特化为指针类型
template <typename T1, typename T2>
class Data<T1*, T2*> {
public:Data() { cout << "Data<T1*, T2*>" << endl; }
private:T1* _d1;T2* _d2;
};// 两个参数偏特化为引用类型
template <typename T1, typename T2>
class Data<T1&, T2&> {
public:Data(const T1& d1, const T2& d2) : _d1(d1), _d2(d2) {cout << "Data<T1&, T2&>" << endl;}
private:const T1& _d1;const T2& _d2;
};


 

(四)类模板特化应用示例
 


以按照小于比较的类模板 Less 为例:
 

cpp   
#include<vector>
#include <algorithm>template<class T>
struct Less {bool operator()(const T& x, const T& y) const {return x < y;}
};int main() {Date d1(2022, 7, 7);Date d2(2022, 7, 6);Date d3(2022, 7, 8);vector<Date> v1;v1.push_back(d1);v1.push_back(d2);v1.push_back(d3);// 可以直接排序,结果是日期升序sort(v1.begin(), v1.end(), Less<Date>());vector<Date*> v2;v2.push_back(&d1);v2.push_back(&d2);v2.push_back(&d3);// 此处直接排序结果错误,因为sort最终按照Less模板中方式比较,只会比较指针,而非指针指向内容// 此时需要特化Less类模板来处理sort(v2.begin(), v2.end(), Less<Date*>());return 0;
}// 对Less类模板按照指针方式特化
template<>
struct Less<Date*> {bool operator()(Date* x, Date* y) const {return *x < *y;}
};


 

三、模板的分离编译
 

(一)什么是分离编译
 


一个程序(项目)由若干个源文件共同实现,每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件,这种模式就是分离编译模式。
 


(二)模板的分离编译
 


当模板的声明与定义分离开,在头文件中声明,源文件中定义时,会出现问题。例如:
a.h
 

cpp   
template<class T>
T Add(const T& left, const T& right);a.cppcpp   
template<class T>
T Add(const T& left, const T& right) {return left + right;
}main.cppcpp   
#include "a.h"
int main() {Add(1, 2);Add(1.0, 2.0);return 0;
}


 
在这种情况下, a.cpp 中编译器没看到对 Add 模板函数的实例化,不会生成具体的加法函数; main.cpp 编译后在链接时找不到 Add<int> 与 Add<double> 的具体代码,就会报错。
 

(三)解决方法
 


1. 将声明和定义放到一个文件“xxx.hpp”里或者 xxx.h 也可以,推荐这种方式。
 
2. 模板定义的位置显式实例化,但这种方法不实用,不推荐。

 

cpp   
template<class T>
T Add(const T& left, const T& right);a.cppcpp   
template<class T>
T Add(const T& left, const T& right) 
{return left + right;
}// template
//int Add(const int& left, const int& right) 
// template
//double Add(const double& left, const double& right) main.cppcpp   
#include "a.h"
int main() 
{Add(1, 2);Add(1.0, 2.0);return 0;
}


四、模板总结
 

(一)优点
 


1. 模板复用了代码,节省资源,能实现更快的迭代开发,C++的标准模板库(STL)就是基于模板产生的。
 
2. 增强了代码的灵活性,能适应多种数据类型。
 


(二)缺陷
 

1. 模板会导致代码膨胀问题,编译时会针对不同类型实例化出多份代码,也会使编译时间变长。
 
2. 出现模板编译错误时,错误信息非常凌乱,难以定位错误根源。
 
希望通过这篇博客,大家能对C++模板有更深入、全面的理解,在今后的编程中能更好地运用模板特性编写出高质量、可复用的代码。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词