【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;就会调用原有的类模板:

相关文章
|
3月前
|
存储 算法 C++
C++ STL 初探:打开标准模板库的大门
C++ STL 初探:打开标准模板库的大门
127 10
|
5月前
|
编译器 C++
【C++】——初识模板
【C++】——初识模板
【C++】——初识模板
|
6月前
|
程序员 C++
C++模板元编程入门
【7月更文挑战第9天】C++模板元编程是一项强大而复杂的技术,它允许程序员在编译时进行复杂的计算和操作,从而提高了程序的性能和灵活性。然而,模板元编程的复杂性和抽象性也使其难以掌握和应用。通过本文的介绍,希望能够帮助你初步了解C++模板元编程的基本概念和技术要点,为进一步深入学习和应用打下坚实的基础。在实际开发中,合理运用模板元编程技术,可以极大地提升程序的性能和可维护性。
|
2月前
|
安全 编译器 C++
【C++11】可变模板参数详解
本文详细介绍了C++11引入的可变模板参数,这是一种允许模板接受任意数量和类型参数的强大工具。文章从基本概念入手,讲解了可变模板参数的语法、参数包的展开方法,以及如何结合递归调用、折叠表达式等技术实现高效编程。通过具体示例,如打印任意数量参数、类型安全的`printf`替代方案等,展示了其在实际开发中的应用。最后,文章讨论了性能优化策略和常见问题,帮助读者更好地理解和使用这一高级C++特性。
66 4
|
2月前
|
算法 编译器 C++
【C++】模板详细讲解(含反向迭代器)
C++模板是泛型编程的核心,允许编写与类型无关的代码,提高代码复用性和灵活性。模板分为函数模板和类模板,支持隐式和显式实例化,以及特化(全特化和偏特化)。C++标准库广泛使用模板,如容器、迭代器、算法和函数对象等,以支持高效、灵活的编程。反向迭代器通过对正向迭代器的封装,实现了逆序遍历的功能。
37 3
|
2月前
|
编译器 C++
【c++】模板详解(1)
本文介绍了C++中的模板概念,包括函数模板和类模板,强调了模板作为泛型编程基础的重要性。函数模板允许创建类型无关的函数,类模板则能根据不同的类型生成不同的类。文章通过具体示例详细解释了模板的定义、实例化及匹配原则,帮助读者理解模板机制,为学习STL打下基础。
34 0
|
3月前
|
编译器 程序员 C++
【C++打怪之路Lv7】-- 模板初阶
【C++打怪之路Lv7】-- 模板初阶
24 1
|
3月前
|
存储 编译器 C++
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
55 9
|
3月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
75 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
3月前
|
算法 编译器 C++
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
101 2