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

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

一、模板参数

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

1.类型形参

出现在模板参数列表中,跟在class或typename之后的参数类型名称。如下代码中跟在class后的T就是类型形参:

1. template<class T>
2. void Swap(T& a, T& b)
3. {
4.  T temp = a;
5.  a = b;
6.  b = temp;
7. }

2.非类型形参

用一个常量作为类或函数模板的一个参数,在类或函数模板中把这个参数当成常量来用,如下代码中的N就是非类型形参,它是模板的另外一个参数:

1. //非类型模板参数
2. template<class T,size_t N>//N被当作常量,不允许被修改
3. class Car
4. {
5. private:
6.  T _number[N];//汽车数量
7. };
8. 
9. int main()
10. {
11.   Car<int, 3> car1;//N=3
12.   Car<int, 20> car2;//N=20
13. 
14.   return 0;
15. }

可以使用缺省的模板参数

1. //非类型模板参数
2. template<class T = int, size_t N = 100>//缺省模板参数
3. class Car
4. {
5. private:
6.  T _number[N];//汽车数量
7. };
8. 
9. int main()
10. {
11.   Car<int, 3> car1;//N=3
12.   Car<int, 20> car2;//N=20
13.   Car<> car3;//使用了缺省的模板参数
14.   return 0;
15. }

注意:

(1)非类型模板参数必须是整形,不允许其他类型。

template<double N>//N是非类型模板参数,编译报错,类型非法,不允许double型

(2)非类型的模板参数必须在编译期就能确认结果。

1. //非类型模板参数
2. template<class T, size_t N>//模板参数没有给默认值
3. class Car
4. {
5. private:
6.  T _number[N];//汽车数量
7. };
8. 
9. int main()
10. {
11.     Car<int> car4;//编译报错,没有指定非类型模板参数的值
12. return 0;
13. }

二、模板的特化

有时候,编译默认函数模板或者类模板不能正确处理需要的逻辑,需要针对指定类型进行特殊化处理,就要做模板的特化。

比如如下代码:

1. template<class T>
2. bool IsEqual(const T& T1, const T& T2)
3. {
4.  return T1 == T2;
5. }
6. void Test()
7. {
8.  char c1[] = "C++";
9.  char c2[] = "C++";
10.   cout << IsEqual(c1, c2) << endl;
11. 
12.   const char* p1 = "C++";
13.   const char* p2 = "C++";
14.   cout << IsEqual(p1, p2) << endl;
15. 
16. }
17. 
18. int main()
19. {
20.   Test();
21.   return 0;
22. }

发现打印结果一个为0,一个为1:

c1和c2是数组,在栈上,c1是第一个数组的地址,c2是第二个数组的地址,c1和c2分别把常量区的字符串"C++"拷贝过去了,c1是第一个数组的地址,c2是第二个数组的地址,所以它俩不相等。

p1和p2是指针,都指向常量字符串"C++","C++"位于常量区,p1和p2里面存的都是地址,都存的是"C++"的地址,所以p1和p2相等。

虽然p1和p2的比较结果是1,是正确的。但是比较两个字符串是否相等,应该比较的是这两个字符串的ASCII码,而不是直接用==来比较。这就需要模板的特化。

模板的特化是在原有模板的基础上,针对特殊类型,所进行特殊化的实现方式,特化的本质是显式指定实例化的模板。模板特化分为函数模板特化和类模板特化。

1.函数模板特化

函数模板特化的步骤:

(1)必须有基础模板函数

(2)template后面跟一对空的尖括号<>

(3)函数名后跟一对尖括号,用来指定特化的类型

(4)函数形参表:必须要和模板函数的基础参数类型完全相同,否则编译器报错。

如上面的字符串比较不能用==来判断字符串是否相等,需要进行模板特化,用strcmp来比较:

1. #include<iostream>
2. using namespace std;
3. 
4. //函数模板
5. template<class T>
6. bool IsEqual(const T& T1, const T& T2)
7. {
8.  return T1 == T2;
9. }
10. 
11. //标准的模板特化
12. template<>
13. bool IsEqual<const char*>(const char* const& left, const char* const& right)
14. {
15.   if (strcmp(left, right) == 0)
16.   {
17.     return true;
18.   }
19.   return false;
20. }
21. 
22. void Test()
23. {
24.   const char* p1 = "C++";
25.   const char* p2 = "C++";
26.   cout << IsEqual(p1, p2) << endl;
27. }
28. 
29. int main()
30. {
31.   Test();
32.   return 0;
33. }
34.

以上第 11-19行是标准的模板特化的写法,为了实现简单,通常都将函数直接给出:

1. //简写的模板板特化
2. bool IsEqual(char* left, char* right)
3. {
4.  if (strcmp(left, right) == 0)
5.  {
6.    return true;
7.  }
8.  return false;
9. }

2.类模板特化

类模板在没有写类特化之前,调的都是原模板的,如下代码,定义了类模板:

1. #include<iostream>
2. using namespace std;
3. 
4. //类模板
5. template<class T1, class T2>
6. class Data
7. {
8. public:
9.  Data()
10.   {
11.     cout << "Data<T1,T2>" << endl;
12.   }
13. };
14. 
15. void Test_Class()
16. {
17.   Data<int, int> d1;
18.   Data<int, char> d2;
19. }
20. 
21. int main()
22. {
23.   return 0;
24. }

类模板分为全特化和偏特化,但是类模板只有一种写法,没有简写形式

(1)全特化

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

比如想把T1指定成int,T2指定成char

1. #include<iostream>
2. using namespace std;
3. 
4. //类模板
5. template<class T1, class T2>
6. class Data
7. {
8. public:
9.  Data()
10.   {
11.     cout << "Data<T1,T2>" << endl;
12.   }
13. };
14. 
15. //类模板的全特化,将T1指定成int,T2指定成char
16. template<>
17. class Data<int, char>
18. {
19. public:
20.   Data()
21.   {
22.     cout << "Data<int,char>" << endl;
23.   }
24. private:
25.   int _d1;
26.   char _d2;
27. };
28. 
29. void Test_Class()
30. {
31.   Data<int, int> d1;
32.     Data<int, double> d2;
33.   Data<int, char> d3;
34. }
35. 
36. int main()
37. {
38.   return 0;
39. }

那么Data<int, char> d3;就会去调用全特化的模板。Data<int, int> d1;和Data<int, double> d2;就会调用原有的类模板:

相关文章
|
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++中的模板与泛型编程技术深度解析
|
22天前
|
存储 算法 程序员
C++模板编程与泛型技术探秘
这篇文章探讨了C++中的模板编程和泛型技术,这两种技术增强了代码复用和抽象能力。文章介绍了函数模板和类模板的概念,通过示例展示了如何定义和使用它们。泛型技术是一种编程范式,强调编写与类型无关的代码,提高代码复用性和灵活性。C++11后的版本通过类型萃取和变长模板参数进一步扩展了模板功能。模板和泛型广泛应用在数据结构、算法、库和框架的开发中,如STL。掌握这些技术有助于编写更高效、灵活的代码,并推动软件开发的创新和进步。
|
25天前
|
编译器 C++
【C++】模板进阶 -- 详解
【C++】模板进阶 -- 详解