• C++08函数模板


    1.自动推导类型

    在C语言和C++98中,auto 关键字用于修饰变量(自动存储的局部变量)。

    在C++11中,赋予了auto 全新的含义,不再用于修饰的变量,而是作为一个类型指示符,指示编译器在编译时推导auto声明的变量的数据类型。

    在Linux 平台下,编译需要加-std=c++11 参数。

    1. #include
    2. using namespace std;
    3. // 如果初始化变量的时候不定义类型,那么会使用auto关键字
    4. // 根据变量赋值,自动推导出相关类型
    5. int main() {
    6. auto a = 3; cout << "a=" << a << endl;
    7. auto b = 3.3; cout << "b=" << b << endl;
    8. auto c = "鲁班"; cout << "c =" << c << endl;
    9. system("Pause");
    10. }

     注意事项:

    1. auto声明的变量必须在定义时初始化
    2. 初始化的右值可以是具体的数值,也可以是表达式和函数的返回值
    3. auto不能作为函数的形参类型
    4. auto不能直接声明数组
    5. auto不能定义类的非静态成员变量

     auto关键字的真正用途:

    1. 代替冗长复杂的变量声明
    2. 在模板中,用于声明依赖模板参数的变量。
    3. 函数模板依赖模板参数的返回值
    4. 用于lambda 表达式中

     auto关键字可以计算两个不同类型的值

    1. #include
    2. using namespace std;
    3. template<typename T1, typename T2>
    4. void func(T1 x, T2 y) {
    5. auto tmp = x + y;
    6. cout << tmp << endl;
    7. }
    8. int main() {
    9. short a = 1;
    10. char b = 2;
    11. func(a, b);
    12. system("Pause");
    13. return 0;
    14. }

    2.函数模板

     先看一段代码:如果我们需要更换两个变量的值,根据变量值的不同,需要不断的重载Swap函数,函数中的tmp变量类型也会改变,其他地方都一样。

    1. #include
    2. using namespace std;
    3. // 交换两int值
    4. void Swap(int &a ,int &b) {
    5. int tmp = a;
    6. b = a;
    7. a = tmp;
    8. }
    9. // 交换两double值
    10. void Swap(double& a, double& b) {
    11. double tmp = a;
    12. b = a;
    13. a = tmp;
    14. }
    15. // 交换两字符串值
    16. void Swap(string& a, string& b) {
    17. string tmp = a;
    18. b = a;
    19. a = tmp;
    20. }
    21. int mian() {
    22. }

    为了避免这种麻烦,利用模型来生成相应的函数代码,即函数模板:

    1. 函数模板是通用的函数描述,使用任意类型(泛型)来描述函数
    2. 编译的时候,编译器推导实参的数据类型,根据实参的数据类型和函数模板,生成该类型的函数定义
    3. 生成函数定义的过程被称为实例化。

    创建交换两个变量的函数模板:

    1. #include
    2. using namespace std;
    3. // 创建一个函数模板,交换两个变量的值
    4. // 定义模板,这里anytype可以随便取名,但是需要注意和下面一致
    5. // 函数模板用typename 类模板用 class
    6. template <typename T>
    7. void Swap(T& a, T& b) {
    8. T tmp = a;
    9. a = b;
    10. b = tmp;
    11. }
    12. int main() {
    13. int a = 1, b = 2;
    14. cout << a << b << endl;
    15. Swap(a, b);
    16. cout << a << b << endl;
    17. system("Pause");
    18. return 0;
    19. }

    注意事项:

    1. 可以为类的成员函数创建模板,但不能是虚函数和析构函数
    2. 使用函数模板时,必须明确数据类型,确保实参与函数模板能匹配上
    3. 使用函数模板时,推导的数据类型必须适应函数模板中的代码
    4. 使用函数模板时,如果是自动类型推导,不会发生隐式类型转换,如果显式指定了函数模板的数据类型,可以发生隐式类型转换
    5. 函数模板支持多个通用数据类型的参数
    1. #include
    2. using namespace std;
    3. class Fruit {
    4. public:
    5. // 构造函数
    6. template <typename T>
    7. Fruit(T a) {
    8. cout << "a=" << a << endl;
    9. }
    10. // 用到模板的地方在上面都要加这一句
    11. template <typename T1,typename T2>
    12. void show(T1 b,T2 c) {
    13. cout << "b=" << b << endl;
    14. cout << "c=" << c << endl;
    15. }
    16. };
    17. int main() {
    18. Fruit apple("烟台红苹果");
    19. apple.show("真的甜","好吃");
    20. system("Pause");
    21. return 0;
    22. }

     函数模板的具体化

    语法:

    template<>void 函数模板名<数据类型>(参数列表)

    template<>void 函数模板名(参数列表)

    {

         // 函数体

    }

    1. #include
    2. using namespace std;
    3. class Fruit {
    4. public:
    5. // 构造函数
    6. Fruit(const string& f_name,int f_gram) {
    7. m_gram = f_gram;
    8. m_name = f_name;
    9. }
    10. void show_gram() {
    11. cout << this->m_name << this->m_gram << endl;
    12. }
    13. string m_name;
    14. int m_gram;
    15. };
    16. // 函数模板
    17. template<typename T>
    18. void Swap(T& a, T& b) {
    19. T tmp = a;
    20. a = b;
    21. b = tmp;
    22. cout << "调用了Swap(T& a, T&b)" << endl;
    23. }
    24. //具体化函数
    25. template<>void Swap(Fruit& f1, Fruit& f2) {
    26. int tmp = f1.m_gram;
    27. f1.m_gram = f2.m_gram;
    28. f2.m_gram = tmp;
    29. cout << "调用了Swap(Fruit& f1, Fruit& f2)" << endl;
    30. }
    31. int main() {
    32. Fruit apple("苹果", 12), orange("橘子", 55);
    33. apple.show_gram();
    34. orange.show_gram();
    35. Swap(apple, orange);
    36. apple.show_gram();
    37. orange.show_gram();
    38. system("Pause");
    39. return 0;
    40. }

    1. 具体化优先于常规模板,普通函数优先于具体化
    2. 如果希望使用函数模板,可以用空模板参数强制使用函数模板
    3. 如何函数模板能产生更好的匹配,将优先于非函数模板

    声明和定义分开

    函数模板的定义和声明都是在头文件中,普通函数和函数模板的具体化版本是分开的。

    main.cpp

    1. #include
    2. #include"public.h"
    3. using namespace std;
    4. int main() {
    5. Swap(1, 1); // 使用普通函数
    6. Swap('c', 'd'); // 使用函数模板
    7. Swap<>(1, 1); // 使用函数模板具体化版本
    8. system("Pause");
    9. return 0;
    10. }

     头文件public.h:

    1. #pragma once
    2. #include
    3. using namespace std;
    4. void Swap(int a, int b); // 普通函数
    5. template<typename T> // 函数模板
    6. void Swap(T a, T b) {
    7. cout << "使用了函数模板" << endl;
    8. }
    9. template<>
    10. void Swap(int a, int b); // 函数模板具体化版本

    源文件public.cpp

    1. #include "public.h"
    2. void Swap(int a, int b) {
    3. cout << "使用了普通函数" << endl;
    4. }
    5. template<>
    6. void Swap(int a, int b) {
    7. cout << "使用了具体化的函数模板" << endl;
    8. }

    3.类模板

    template <class T>

    class 类模板名

    {

            类的定义

    }

    1. #include
    2. using namespace std;
    3. template<class T1,class T2>
    4. class AA {
    5. public:
    6. T1 m_a;
    7. T2 m_b;
    8. AA(T1 a, T2 b) :m_a(a), m_b(b){}
    9. //构造函数
    10. AA() {}
    11. // 可以用于成员函数的返回值
    12. // 即a是什么类型,这里geta返回的也是什么类型
    13. T1 geta() {
    14. T1 num = 2; // 这里也可以定义一个和a相同类型的与a相加
    15. return m_a + num;
    16. }
    17. T2 getb() {
    18. T1 num = 2;
    19. return m_b;
    20. }
    21. };
    22. int main() {
    23. AA<int, double>a; // 用模板类AA创建对象
    24. a.m_a = 2;
    25. a.m_b = 3;
    26. cout << "a.geta()=" << a.geta() << endl;
    27. cout << "a.getb()=" << a.getb() << endl;
    28. system("Pause");
    29. return 0;
    30. }

    可以用new创建模板类对象:main函数这么写

    1. int main() {
    2. AA<int, double>*a=new AA<int, double>(1,2); // 用模板类AA创建对象
    3. cout << "a.geta()=" << a->geta() << endl;
    4. cout << "a.getb()=" << a->geta() << endl;
    5. delete a;
    6. system("Pause");
    7. return 0;
    8. }

    类模板的具体化

    1. #include
    2. using namespace std;
    3. //类模板
    4. template<class T1,class T2>
    5. class AA {
    6. T1 mx;
    7. T2 my;
    8. AA(const T1 x, const T2 y) :mx(x), my(y) { cout << "类模板,构造函数" << endl; }
    9. void show()const;//类内声明,类外实现
    10. };
    11. // 成员函数类外实现
    12. template<class T1,class T2>
    13. void AA::show()const {
    14. cout << "类模板:x=" << mx << ",y=" << my << endl;
    15. };
    16. //类模板完全具体化
    17. template<>class AA<int, string> {
    18. public:
    19. int mx;
    20. string my;
    21. AA(const int x, const string y) :mx(x), my(y) { cout << "完全具体化:构造函数" << endl; };
    22. void show()const;
    23. };
    24. void AA<int, string>::show()const {
    25. cout << "完全具体化x=" << mx << ",y=" << my << endl;
    26. };
    27. //类模板部分显示具体化
    28. template<class T1>
    29. class AA { // T1通用,string具体
    30. public:
    31. T1 mx;
    32. string my;
    33. AA(T1 x, const string y) :mx(x), my(y) { cout << "部分具体化:构造函数 " << endl; };
    34. void show()const {
    35. cout << "部分具体化x=" << mx << ",y=" << my << endl;
    36. };
    37. };
    38. int main() {
    39. //具体化程度高的类优先于具体化程度低的类,具体化的类优先于没有具体化的类
    40. AA<int, string>aa(22, "光头强");
    41. aa.show();
    42. system("Pause");
    43. return 0;
    44. }

    类模板的继承

    1.  模板类继承普通类(常见)

    2. 普通类继承模板类的实例版本

    3. 普通类继承模板类(常见)

    4. 模板类继承模板类

    5. 模板类继承模板参数给出的基类(不能是模板类)

    下面演示第一种:模板类继承普通类

    1. #include
    2. using namespace std;
    3. class AA { // 普通类AA
    4. public:
    5. int m_a;
    6. AA(int a) :m_a(a) { cout << "调用AA构造函数" << endl; }
    7. void func1() { cout << "调用func1函数:m_a=" << m_a << endl; }
    8. };
    9. template<class T1,class T2>
    10. class BB:public AA // 模板类BB
    11. {
    12. public:
    13. T1 m_x;
    14. T2 m_y;
    15. BB(const T1 x, const T2 y,int a):AA(a),m_x(x), m_y(y) { cout << "调用BB构造函数" << endl; }
    16. void func2() { cout << "调用func2函数,x+y=" << m_x <<",m_y=" << m_y << endl; }
    17. };
    18. int main() {
    19. BB<int, string>bb(22, "光头强", 6666);
    20. bb.func1();
    21. cout << "--------------------" << endl;
    22. bb.func2();
    23. system("Pause");
    24. return 0;
    25. }

    第三种情况:普通类继承模板类

    1. #include
    2. using namespace std;
    3. template<class T1,class T2>
    4. class BB // 模板类BB
    5. {
    6. public:
    7. T1 m_x;
    8. T2 m_y;
    9. BB(const T1 x, const T2 y):m_x(x), m_y(y) { cout << "调用BB构造函数" << endl; }
    10. void func2() { cout << "调用func2函数,x+y=" << m_x <<",m_y=" << m_y << endl; }
    11. };
    12. template<class T1, class T2>
    13. class AA:public BB { // 普通类AA
    14. public:
    15. int m_a;
    16. AA(int a,const T1 x,const T2 y) :BB(x,y),m_a(a) { cout << "调用AA构造函数" << endl; }
    17. void func1() { cout << "调用func1函数:m_a=" << m_a << endl; }
    18. };
    19. int main() {
    20. AA<int, string>aa(1,22, "光头强");
    21. aa.func1();
    22. cout << "--------------------" << endl;
    23. aa.func2();
    24. system("Pause");
    25. return 0;
    26. }

    类模板的成员模板

    1. #include
    2. using namespace std;
    3. template<class T1,class T2>
    4. class AA {
    5. public:
    6. T1 m_x;
    7. T2 m_y;
    8. AA(const T1 x,const T2 y):m_x(x),m_y(y){}
    9. void show() { cout << "m_x=" << m_x << " m_y=" << m_y << endl; }
    10. template<class T> // 类模板
    11. class BB
    12. {
    13. public:
    14. T m_a;
    15. T1 m_b;
    16. BB(){}
    17. void show() { cout << "m_a=" << m_a << " m_b=" << m_b << endl; }
    18. };
    19. BBbb; // bb就是类模板AA的一个成员
    20. //函数模板
    21. template<typename TF>
    22. void showf(TF tt) { cout << "tt=" << tt << endl; }
    23. };
    24. int main() {
    25. AA<int, string>a(22, "光头强");
    26. a.show();
    27. a.bb.m_a = "熊大";
    28. a.bb.show();
    29. a.showf("看我大卫天龙");
    30. system("pause");
    31. return 0;
    32. }

  • 相关阅读:
    数字求和(C++)
    第四章:指令系统
    ANR问题分析的一般套路
    Android:实现手机前后摄像头预览同开
    YOLOV:图像对象检测器在视频对象检测方面表现也很不错
    哺乳期哪些事不能做?
    安装nodejs
    16、Pytorch Lightning入门
    Docker实现Redis Cluster集群 哈希槽分区进行亿级数据存储
    反片语 set+哈希表 就C++代码而言,我很短
  • 原文地址:https://blog.csdn.net/weixin_45231460/article/details/128116989