【C++】-- 模板进阶(二)

简介: 【C++】-- 模板进阶

(2)偏特化

偏特化是任何针对模板参数进一步进行条件限制的特化版本。偏特化分为两种表现方式:

①部分特化:把模板参数类表中的一部分参数特化

1. //偏特化-部分特化,把第二个参数特化为double
2. template<class T1>
3. class Data<T1, double>
4. {
5. public:
6.  Data()
7.  {
8.    cout << "Data<T1,T2>" << endl;
9.  }
10. private:
11.   T1 _d1;
12.   double _d2;
13. };

这时候d2就会去调这个偏特化 :

②对参数进一步限制:对模板参数做更进一步的条件限制

可以将参数偏特化为指针类型 :

1. //偏特化-两个参数偏特化为指针类型,只指定指针,什么类型的指针都可以
2. template<typename T1,typename T2>
3. class Data<T1*, T2*>
4. {
5. public:
6.  Data()
7.  {
8.    cout << "Data<T1*,T2*>" << endl;
9.  }
10. private:
11.   T1 _d1;
12.   T2 _d2;
13. };
1. void Test_Class()
2. {
3.  Data<int, int> d1;
4.  Data<int, double> d2;
5.  Data<int, char> d3;
6.  Data<char*, char*> d4;//会调用两个参数偏特化为指针类型的偏特化
7. }

也可以将参数偏特化为引用类型:

1. //偏特化-两个参数偏特化为引用类型,只指定引用,什么类型的引用都可以
2. template<typename T1, typename T2>
3. class Data<T1&, T2&>
4. {
5. public:
6.  Data(const T1& d1,const T2& d2)
7.    :_d1(d1)
8.    ,_d2(d2)
9.  {
10.     cout << "Data<T1&,T2&>" << endl;
11.   }
12. private:
13.   const T1& _d1;
14.   const T2& _d2;
15. };
1. void Test_Class()
2. {
3.  Data<int, int> d1;
4.  Data<int, double> d2;
5.  Data<int, char> d3;
6.  Data<char*, char*> d4;//会调用两个参数偏特化为指针类型的偏特化
7.  Data<double&, double&> d5(2.1, 3.2);//会调用两个参数偏特化为引用类型的偏特化
8. }

最后,编译器匹配参数时,会自动匹配最匹配的那个,编译器实例化之后就没有模板了,实例化之后就会把T1&替换成double&,把T2&替换成double&,就变成了普通类。

假如参数类型一个是指针,一个是引用呢?将一个参指定为指针类型,另外一个参数指定为引用类型

1. //偏特化-一个参数偏特化为指针类型,一个参数偏特化为引用类型
2. template<typename T1, typename T2>
3. class Data<T1*, T2&>
4. {
5. public:
6.  Data()
7.  {
8.    cout << "Data<T1*,T2&>" << endl;
9.  }
10. };
Data<int*, double&> d6;//会调用一个参数偏特化为指针类型,一个参数偏特化为引用类型的偏特化

三、模板分离编译

分离式编译:一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,将所有目标文件连接起来形成单一的可执行文件的过程称为分离编译模式。

1.模板支持分离编译吗

对于分离式编译的模板:

template.h

1. template<class T>
2. T Add(const T& left, const T& right);

template.cpp

1. #include "template.h"
2. 
3. template<class T>
4. T Add(const T& left, const T& right)
5. {
6.  return left + right;
7. }

template-main.cpp  

1. #include "template.h"
2. 
3. int main()
4. {
5.  Add(1, 2);
6.  Add(1.0, 2.0);
7. 
8.  return 0;
9. }

上述代码运会报错:

2.为什么模板不支持分离编译

程序要运行,需要经过预处理、编译、汇编、链接4个阶段

(1)预处理

包含头文件、宏替换、、条件编译、删除注释

(2)编译

语法分析、词法分析、语义分析,符号汇总

(3)汇编

汇编代码转换成机器指令 、生成符号表

(4)链接

链接目标文件和连接库、合并符号表、重定位

预处理阶段,#include "template.h"包含头文件,认为会有Add函数的定义。编译时在符号表里填上符号和地址,生成符号表,编译阶段只有函数声明,没有函数定义,如果有人调用了这个符号,就能通过符号表找到这个符号对应的地址。但是函数模板不会生成对应符号。汇编时把符号转换成二进制,这样,机器就可以识别了。链接时会去找函数地址进行合并重定位。

虽然编译时,想生成函数模板对应的符号,但是此时并不知道T是什么,由于在链接之前,各个文件不知道对方的存在,所以template-main.cpp无法告诉template.cpp T具体是什么,template.cpp中无法对T进行实例化,会寄希望于最后一步链接,所以不会生成对应符号。即,定义的地方(template.cpp)不实例化,而实例化的地方(template-main.cpp)没有定义,只有声明。没有实例化T,生成不了函数模板的符号。

3.如何编译模板文件

如何解决函数模板不能生成对应符号,导致程序运行不了的问题呢?有两种方法

(1)显式指定实例化

模板定义时直接指定T的类型,即增加模板的特化,将template.cpp改为:

1. #include "template.h"
2. 
3. template<class T>
4. T Add(const T& left, const T& right)
5. {
6.  return left + right;
7. }
8. 
9. //增加int类型的模板特化
10. template<>
11. int Add<int>(const int& left, const int& right)
12. {
13.   return left + right;
14. }
15. 
16. //增加double类型的模板特化
17. template<>
18. double Add<double>(const double& left, const double& right)
19. {
20.   return left + right;
21. }

(2)将声明和定义放到一个文件中(推荐)

将template.h和template.cpp合并成一个文件,这个文件名可以是template.h,也可以是template.cpp,此时template就只剩下一个文件了。

template.h

1. template<class T>
2. T Add(const T& left, const T& right);
3. 
4. template<class T>
5. T Add(const T& left, const T& right)
6. {
7.  return left + right;
8. }

template.main不变

1. #include "template.h"
2. 
3. int main()
4. {
5.  Add(1, 2);
6.  Add(1.0, 2.0);
7. 
8.  return 0;
9. }

编译通过。

相关文章
|
1天前
|
算法 安全 编译器
【C++进阶】模板进阶与仿函数:C++编程中的泛型与函数式编程思想
【C++进阶】模板进阶与仿函数:C++编程中的泛型与函数式编程思想
|
1天前
|
JavaScript 前端开发 编译器
【C++初阶】C++模板编程入门:探索泛型编程的奥秘
【C++初阶】C++模板编程入门:探索泛型编程的奥秘
|
2天前
|
编译器 C++ 容器
【C++语言】模板(内附精美思维导图)
【C++语言】模板(内附精美思维导图)
|
12天前
|
存储 编译器 C++
6.C++模板(超全)
6.C++模板(超全)
|
18天前
|
编译器 C语言 C++
从C语言到C++_21(模板进阶+array)+相关笔试题(下)
从C语言到C++_21(模板进阶+array)+相关笔试题
24 2
|
18天前
|
编译器 C语言 C++
从C语言到C++_21(模板进阶+array)+相关笔试题(上)
从C语言到C++_21(模板进阶+array)+相关笔试题
24 0
|
22天前
|
存储 算法 C++
高效利用C++ STL库:标准模板库的使用技巧
本文介绍了C++ STL(标准模板库)的高效使用技巧,包括选择合适的容器类型、使用`emplace_back`而非`push_back`、预分配容器空间和范围for循环遍历容器。此外,还讨论了STL算法的运用,如用算法替代手动循环、使用lambda表达式和进行容器操作。通过这些技巧,开发者可以提升C++代码的性能和可读性。
|
22天前
|
程序员 编译器 C++
C++中的模板与泛型编程技术深度解析
C++中的模板与泛型编程技术深度解析
|
23天前
|
存储 算法 程序员
C++模板编程与泛型技术探秘
这篇文章探讨了C++中的模板编程和泛型技术,这两种技术增强了代码复用和抽象能力。文章介绍了函数模板和类模板的概念,通过示例展示了如何定义和使用它们。泛型技术是一种编程范式,强调编写与类型无关的代码,提高代码复用性和灵活性。C++11后的版本通过类型萃取和变长模板参数进一步扩展了模板功能。模板和泛型广泛应用在数据结构、算法、库和框架的开发中,如STL。掌握这些技术有助于编写更高效、灵活的代码,并推动软件开发的创新和进步。
|
25天前
|
编译器 C++
【C++】模板进阶 -- 详解
【C++】模板进阶 -- 详解