Share this post on:

函数模板

  • 函数中用到的未知类型

  • 函数模板的调用

    • 隐式调用:根据数据类型自动推导模板类型
    • 显式调用:显示传入类型,格式Func<Type>(arg)
  • 模板可以缺省(不传参则自动赋初值)

  • 模板可以写变量

  • 一个类的成员函数也可以是模板

    #include 
    #include 
    #include 
    
    using namespace std;
    
    // 另一个类的成员函数是函数模板
    class MM
    {
    public:
      //函数模板
    template 
    void print(T data)
    {
        cout << data << endl;
    }
    
    protected:
    };
    
    //函数模板重载
    //函数模板和普通函数
    template 
    void printSum(T1 a, T2 b, T3 c)
    {
      cout << "调用函数模板" << endl;
      cout << a << endl;
      cout << b << endl;
      cout << c << endl;
    }
    void printSum(int a, int b, int c)
    {
      cout << "调用普通函数" << endl;
      cout << a << endl;
      cout << b << endl;
      cout << c << endl;
    }
    
    int main()
    {
    MM test;
    test.print(3);
      test.print(3.33);
      test.print("asvsa");
    
      printSum(1, 2, 3); //隐式调用
      printSum(1, 2, 3); //显示调用
      printSum(33, 2.333, "abcd");
    
    return 0;
    }

类模板

  • 类用到了位置类型
  • 多文件中,类模板不能把声明和实现分开
  • 类模板在调用时必须显示调用,不能隐式调用
  • 类模板不是一个完整类,所以在用到类名的地方,必须用类名<类型>方式去使用
  • 类模板的特化
#include <iostream>
#include <string>
#include <array>

using namespace std;

template <class T1, class T2>
class Test
{
public:
    Test() {}
    Test(T1 a, T2 b) : a(a), b(b) {}
    void print();

protected:
    T1 a;
    T2 b;
};
void run_test()
{
    Test<string, string> test("abc", "abcd"); //类模板必须显示实例化
    Test<int, string> *p = new Test<int, string>(6, "hhan");
    test.print();
    p->print();
}

// 用到类型的地方必须用类名<类型>的方式使用
template <class T1, class T2>
void Test<T1, T2>::print()
{
    cout << a << endl;
    cout << b << endl;
}
template <class T1, class T2>
class Test2 : public Test<T1, T2>
{
public:
    Test2() {}
protected: 
};

template <class T, int size>
class MyArray
{
public:
    MyArray()
    {
        memory = new T[size];
    }
protected:
    T* memory;
};
void testMyArray()
{
    MyArray<int, 3> arr;

    array<Test<int, string>, 5> data;
    //上面一句话等效于下面两句话
    using dataT = Test<int, string>;
    array<dataT, 5> data1;
};

//函数特化
template <class T1, class T2, class T3>
class Data
{
public:
    Data(T1 a, T2 b, T3 c) : a(a), b(b), c(c)
    {
        cout << "调用原生模板" << endl;
    }
protected:
    T1 a;
    T2 b;
    T3 c;
};

//局部特化,特殊化处理
template <class T>
class Data<T, T, T>
{
public:
    Data(T a, T b, T c) : a(a), b(b), c(c)
    {
        cout << "调用局部特化" <<endl;
    }
protected:
    T a, b, c;
};

//完全特化 --> 针对特定数据进行特定处理
template<>
class Data<int, string, string>
{
public:
    Data(int a, string b, string c) : a(a), b(b), c(c)
    {
        cout << "调用完全特化" << endl;
    }
protected:
    int a;
    string b;
    string c;
};
void testCallData()
{
    Data<int, string, string> dataTest(2, "hhan", "ann");
    Data<string, string, string> dataTest2("huysj", "hhan", "ann");
    Data <int, double, string> dataTest3(1, 3.14, "hhan");
}

int main()
{
    run_test();
    testCallData();
    return 0;
}

可变模板

  • 知道折叠参数的类型: _Ty… args

    • 类型:...Args
    • 参数包(变量名):args
  • 知道折叠参数的展开方式

#include <iostream>
#include <stdio.h>
#include <string>

using namespace std;

//特化函数
template <class T>
void printData(T data)
{
    cout << data << " ";
}

template <class ... Args>
void print(Args... args)
{
    int array[] = {(printData(args), 0)...};
    cout << endl;
}

int main()
{
    print(1);
    print(1, "hhan");
    print(1, "hhan", "ann");
    return 0;
}

初始化成员

template <class T1, class T2>
class Test
{
public:
    Test(T1 a, T2 b) :a(a), b(b) {}
    void print();

protected:
    T1 a;
    T2 b;
};

其中Test(T1 a, T2 b) :a(a), b(b) {}用于初始化成员列表

成员初始化列表使用冒号(:)后跟初始化表达式,每个初始化表达式由成员变量名和对应的初始化值组成,中间用逗号分隔。

通过使用成员初始化列表,可以直接对成员变量进行初始化,而不需要在构造函数的函数体中使用赋值操作。这样可以提高代码的效率和可读性,并且在某些情况下,成员初始化列表也可以用于初始化常量成员或引用成员

  • 初始化常量

    class Test {
    private:
      const int constantMember;
    
    public:
      Test(int value) : constantMember(value) {}
    };

    常量成员变量只能通过成员初始化列表来初始化,而不能在构造函数的函数体中进行赋值操作

  • 初始化引用成员

    引用成员变量只能在成员初始化列表中进行初始化,而不能在构造函数的函数体中重新绑定到其他对象

    class Test {
    private:
      int& refMember;
    
    public:
      Test(int& value) : refMember(value) {}
    };

初始化成员的其他写法

  • 在构造函数的函数体中使用赋值操作符(=)进行初始化

    Test(T1 a, T2 b) {
      this->a = a;
      this->b = b;
    }
  • 在构造函数的函数体中使用成员初始化列表进行初始化(混合写法)

    Test(T1 a, T2 b) : a(a) {
      this->b = b;
    }
Share this post on:

Leave a Comment

您的电子邮箱地址不会被公开。 必填项已用 * 标注