模板

1. 函数模板

1.1. 函数模板的定义

1.1.1. 前言

利用函数重载的作用来在一个功能上堆需求应用

  1. #include <iostream>
  2. using namespace std;
  3. int compare(int a, int b){
  4. if(a > b){
  5. return 1;
  6. }else if(a < b){
  7. return -1;
  8. }else{
  9. return 0;
  10. }
  11. }
  12. int compare(double a, double b){
  13. if(a > b){
  14. return 1;
  15. }else if(a < b){
  16. return -1;
  17. }else{
  18. return 0;
  19. }
  20. }
  21. int compare(string a, string b){
  22. if(a > b){
  23. return 1;
  24. }else if(a < b){
  25. return -1;
  26. }else{
  27. return 0;
  28. }
  29. }
  30. int main(){
  31. cout << compare(3, 2) << endl;
  32. cout << compare(1.1, 2.1) << endl;
  33. cout << compare(string("hello"), string("world")) << endl;
  34. return 0;
  35. }

1.1.2. 概念与定义语法

  • 有没有原型类似 int compare(T a, T b)的函数?有,如果函数的参数类型或者返回值类型为通用类型,则称为 函数模板
  • 定义语法 ```cpp template<类型形参列表> 返回值类型 函数名(数据形参列表){

}

  1. - 举栗子:
  2. ```cpp
  3. template<typename T>
  4. int compare(T a, T b){
  5. }

1.1.3. 示例代码

  1. #include <iostream>
  2. using namespace std;
  3. template <typename T = int>
  4. int compare(T a, T b){
  5. if(a > b){
  6. return 1;
  7. }else if(a < b){
  8. return -1;
  9. }else{
  10. return 0;
  11. }
  12. }
  13. int main(){
  14. // 类型自动推导用法
  15. cout << compare(3, 2) << endl;
  16. cout << compare(1.1, 2.1) << endl;
  17. cout << compare(string("hello"), string("world")) << endl;
  18. cout << "--------------" << endl;
  19. cout << compare("hello", "world") << endl; // const char*
  20. const char* str1 = "hello";
  21. const char* str2 = "world";
  22. cout << (void*)str1 << endl;
  23. cout << (void*)str2<< endl;
  24. cout << compare(str1, str2) << endl; // const char*
  25. cout << "-----------------" << endl;
  26. // 一般用法
  27. cout << compare<int>(33, 22) << endl;
  28. cout << compare<double>(33.3, 22.2) << endl;
  29. cout << compare<string>(string("hello"), string("kity")) << endl;
  30. // 默认值用法
  31. cout << compare<>(33, 22) << endl;
  32. cout << compare<double>(33.3, 22.2) << endl;
  33. cout << compare<string>(string("hello"), string("kity")) << endl;
  34. return 0;
  35. }

1.2. 类型形参列表

  • typename 用来声明一种类型名,有时也用class来代替typename T1, T2, …是类型形式参数名,代表一种类型

1.3. 函数模板的使用

  • 模板的使用又称为 实例化,调用模板时指定实际类型
  • 一般用法:
    • 函数名<类型实参列表>(数据实参列表);
    • 举例:
      • compare<int>(a, b);
  • 类型形参默认值

    • 在模板声明时,可以指定类型的默认值
      • template<typename T = int>
    • 具有默认值的类型形参,在使用模板时可以不指定类型实参
      • 函数名<>(数据实参列表);
      • eg: compare<>(a,b);
    • 注意,类型形参默认值需要C++11的支持,编译器需要加 -std=C++11
    • 类型形参自动推导
      • compare(a, b); //类型形参的传参为 int
      • compare(a, b); // 类型形参的传参根据 a 和 b的实际类型自动推导出

        1.4. 函数模板的特化定义

        1.4.1. 概念

  • 特化定义是针对某种特殊类型的定义,是对通用定义的补充

  • 比如compare( )模板的通用定义适用于intdoublestring类型,但不使用与const char *那么针对const char *就需要使用特化定义对通用定义进行补充,使模板也适用于const char *

    1.4.2. 语法

    ```cpp template<> 返回值类型 函数名<类型实参类别>(数据形参列表){

}

  1. <a name="FQOkM"></a>
  2. ### 1.4.3. 示例代码
  3. ```cpp
  4. #include <iostream>
  5. #include <cstring>
  6. using namespace std;
  7. // 带类型形参默认值的 函数模板定义(声明)
  8. template <typename T = int>
  9. int compare(T a, T b){
  10. if(a > b){
  11. return 1;
  12. }else if(a < b){
  13. return -1;
  14. }else{
  15. return 0;
  16. }
  17. }
  18. // 函数模板特化定义
  19. template <>
  20. int compare<const char*>(const char* a, const char* b){
  21. if(strcmp(a, b) > 0){
  22. return 1;
  23. }else if(strcmp(a, b) < 0){
  24. return -1;
  25. }else{
  26. return 0;
  27. }
  28. }
  29. int main(){
  30. // 类型自动推导用法
  31. cout << compare(string("hello"), string("world")) << endl;
  32. cout << "--------------" << endl;
  33. cout << compare("hello", "world") << endl; // const char*
  34. const char* str1 = "hello";
  35. const char* str2 = "world";
  36. cout << (void*)str1 << endl;
  37. cout << (void*)str2<< endl;
  38. cout << compare<const char*>(str1, str2) << endl; // const char*
  39. cout << "-----------------" << endl;
  40. return 0;
  41. }

1.5. 调用时的匹配原则

1.5.1. 概念

  • 特化函数模板比通用函数模板优先
  • 函数比函数模板优先

    1.5.2. 示例代码

    ```cpp

    include

    include

    using namespace std;

// 通用模板定义 template int compare(T a, T b){ cout << “通用” << endl; if(a > b){ return 1; }else if(a < b){ return -1; }else{ return 0; } }

// 函数模板特化定义 template <> int compare(const char a, const char b){ cout << “特化” << endl; if(strcmp(a, b) > 0){ return 1; }else if(strcmp(a, b) < 0){ return -1; }else{ return 0; } }

// 函数定义 int compare(const char a, const char b){ cout << “函数” << endl; if(strcmp(a, b) > 0){ return 1; }else if(strcmp(a, b) < 0){ return -1; }else{ return 0; } }

int main(){ // 类型自动推导用法 cout << compare(string(“hello”), string(“world”)) << endl; cout << “———————“ << endl; cout << compare(“hello”, “world”) << endl; // const char const char str1 = “hello”; const char str2 = “world”; cout << (void)str1 << endl; cout << (void)str2<< endl; cout << compare(str1, str2) << endl; // const char cout << “————————-“ << endl;

return 0;

}

<a name="STRmW"></a>
# 2. 类模板
<a name="R0Du3"></a>
## 2.1. 类模板的定义:

- 如果类的定义中存在通用类型,则称为类模板。
- 语法:
```cpp
template <typename T1, typename T2, ...>
class 类名{

};
  • 举栗子
    ```cpp template class Demo{

};


- 示例代码:
```cpp
#include <iostream>
using namespace std;

template <typename T1, typename T2 = double>
class Demo{
    private:
        T1 a;
        T1 b;
    public:
        Demo(T1 a, T1 b){
            this->a = a;
            this->b = b;
        }
        int compare(){
            if(a > b){
                return 1;
            }else if(a < b){
                return -1;
            }else{
                return 0;
            }
        }

        void show(T2 data){
            if(compare() == 0){
                cout << data << endl;
            }else{
                cout << "not equal" << endl;
            }
        }
};

int main(){
    // 一般用法
    Demo<int, double> d(1, 2);
    cout << d.compare() << endl;
    d.show(3.14);

    cout << "-----------------" << endl;
    // 默认值用法
    Demo<int> d1(1, 2);
    cout << d1.compare() << endl;
    d1.show(3.14);

    // 类型自动推导不支持
    //Demo d2(1, 2); // error, 无法推导T2的类型

    cout << "-----------------" << endl;
    Demo<const char*, double> d3("hello", "world");
    cout << d3.compare() << endl;
    cout << "-----------------" << endl;

    return 0;
}

2.2. 类模板的使用

2.2.1. 一般用法(语法)

类名<类型实参列表> 对象名;

2.2.2. 类型形参默认值

  • 模板在定义时,可以指定类型形参的默认值

    template <typename T1, typename T2 = int>
    
  • 具有默认值的类型参数,在使用模板时可以不指定具体类型

    类名<string> 对象名;  // T2的传参值不指定,按默认值int类型
    

    2.2.3. 类模板不支持类型形参自动推导

    类名<类型实参列表> a; // 类型实参列表中指定类型,即 ok
    类名 a;              // error
    

    2.3. 类模板的全特化定义

    2.3.1. 概念与语法

  • 与函数模板的特化类似,类模板的特化定义时针对具体的类型,是对通用定义的补充。
  • 类模板全特化定义(语法):

    特点:类型形参列表为空

template < >
class 类名<类型实参列表>{

};

// 举例:
template < >
class Demo<const char*, int>{

};

2.3.2. 示例代码

#include <iostream>
#include <cstring>
using namespace std;

template <typename T1, typename T2 = double>
class Demo{
    private:
        T1 a;
        T1 b;
    public:
        Demo(T1 a, T1 b){
            this->a = a;
            this->b = b;
        }
        int compare(){
            cout << "通用" << endl;
            if(a > b){
                return 1;
            }else if(a < b){
                return -1;
            }else{
                return 0;
            }
        }

        void show(T2 data){
            if(compare() == 0){
                cout << data << endl;
            }else{
                cout << "not equal" << endl;
            }
        }
};

template < >
class Demo<const char*, int>{
    private:
        const char* a;
        const char* b;
    public:
        Demo(const char* a, const char* b){
            this->a = a;
            this->b = b;
        }
        int compare(){
            cout << "特化" << endl;
            if(strcmp(a, b) > 0){
                return 1;
            }else if(strcmp(a, b) < 0){
                return -1;
            }else{
                return 0;
            }
        }

        void show(int data){
            if(compare() == 0){
                cout << data << endl;
            }else{
                cout << "not equal" << endl;
            }
        }
};

int main(){
    // 一般用法
    Demo<int, double> d(1, 2);
    cout << d.compare() << endl;
    d.show(3.14);

    cout << "-----------------" << endl;
    // 默认值用法
    Demo<int> d1(1, 2);
    cout << d1.compare() << endl;
    d1.show(3.14);

    cout << "-----------------" << endl;
    Demo<const char*, int> d3("hello", "world"); // 调用特化定义
    cout << d3.compare() << endl;
    cout << "-----------------" << endl;

    return 0;
}

2.4. 类模板的偏特化定义

2.4.1. 概念与语法

  • 如果类模板有多个类型形参,特化定义时只特化部分类型形参,称为 偏特化定义,特化全部的全部类型形参就称为 全特化定义。
  • 类模板偏特化定义-(语法)

    注意:函数模板只有全特化,没有偏特化j

template <typename T2>
class 类名<具体类型, T2>{

};

//举例
template <typename T2>
class Demo<const char*, T2>{

};

2.4.2. 示例代码

#include <iostream>
#include <cstring>
using namespace std;

// 通用定义
template <typename T1, typename T2 = double>
class Demo{
    private:
        T1 a;
        T1 b;
    public:
        Demo(T1 a, T1 b){
            this->a = a;
            this->b = b;
        }
        int compare(){
            cout << "通用" << endl;
            if(a > b){
                return 1;
            }else if(a < b){
                return -1;
            }else{
                return 0;
            }
        }

        void show(T2 data){
            if(compare() == 0){
                cout << data << endl;
            }else{
                cout << "not equal" << endl;
            }
        }
};

// 全特化定义
template < >
class Demo<const char*, int>{
    private:
        const char* a;
        const char* b;
    public:
        Demo(const char* a, const char* b){
            this->a = a;
            this->b = b;
        }
        int compare(){
            cout << "特化" << endl;
            if(strcmp(a, b) > 0){
                return 1;
            }else if(strcmp(a, b) < 0){
                return -1;
            }else{
                return 0;
            }
        }

        void show(int data){
            if(compare() == 0){
                cout << data << endl;
            }else{
                cout << "not equal" << endl;
            }
        }
};

// 偏特化定义
template <typename T2>
class Demo<const char*, T2>{
    private:
        const char* a;
        const char* b;
    public:
        Demo(const char* a, const char* b){
            this->a = a;
            this->b = b;
        }
        int compare(){
            cout << "偏特化" << endl;
            if(strcmp(a, b) > 0){
                return 1;
            }else if(strcmp(a, b) < 0){
                return -1;
            }else{
                return 0;
            }
        }

        void show(T2 data){
            if(compare() == 0){
                cout << data << endl;
            }else{
                cout << "not equal" << endl;
            }
        }
};

int main(){
    // 调用通用定义
    Demo<int, double> d(1, 2);
    cout << d.compare() << endl;
    d.show(3.14);

    cout << "-----------------" << endl;
    // 调用特化定义
    Demo<const char*, int> d3("hello", "world"); 
    cout << d3.compare() << endl;
    d3.show(3);

    cout << "-----------------" << endl;
    // 调用偏特化定义
    Demo<const char*, double> d4("hello", "world");
    cout << d4.compare() << endl;
    d4.show(3.14);
    cout << "-----------------" << endl;

    return 0;
}

2.5. 调用时的匹配原则

  • 偏特化类模板比通用类模板优先
  • 全特化类模板比偏特化类模板优先

    3. std::pair

    3.1. 介绍

  • 标准库中的pair是一个类模板,头文件为,在实际使用中使用using namespace std; 在包含文件夹语句后调用,我们使用pair模板时可以不加std::,即 std名空间作用域解析运算符。

  • pair将任意类型的两个数组组合成一个数据对。
  • pair包含两个公有的数据成员first和second
  • pair的用法: | pair p1; | 定义一个空的pair对象,两个成员变量的类型分别为T1和T2。
    T1, T2是具体类型。 | | —- | —- | | pair p1(v1, v2); | 定义一个pair对象,first的类型为T1,值为v1;
    second的类型为T2, 值为v2。 | | p1.first; | 返回对象p1中名为first的公有数据成员 | | p1.second; | 返回对象p1中名为second的公有数据成员 | | p1 == p2; | 如果两个对象的first和second依次相等,则这两个对象相等; | | p1 < p2;
    | 两个pair对象间的小于运算,其定义遵循字典次序.
    如p1.first < p2.first 或者 (p1.first == p2.first)&& (p1.second < p2.second) 则返回ture. |

3.2. 示例代码

#include <iostream>
#include <utility>
using namespace std;

ostream& operator<<(ostream& out, const pair<int, int>& pr){
    out << "(" << pr.first << ", " << pr.second << ")";
    return out;
}

template <typename K, typename V>
ostream& operator<<(ostream& out, const pair<K, V>& pr){
    out << "(" << pr.first << ", " << pr.second << ")";
    return out;
}

int main(){
    pair<int, int> c1;
    pair<int, int> c2(1, 2);

    cout << c2.first << " " << c2.second << endl;

    c1.first = 1;
    c1.second = 3;
    cout << c1.first << " " << c1.second << endl;

    cout << (c1 == c2) << endl;
    cout << (c1 < c2) << endl;

    cout << c1 << endl; // --> (1, 3)

    pair<string, double> sd(string("YYW"), 59.5);
    cout << sd << endl; // --> (YYW, 59.5)

    return 0;
}