函数模板、类模板

一、函数模板

template<typename T>   // typename/class 都可以,这两关键字,表示 T 是一种类型
// 如果有过个类型,则用 template<typename T1, typename T2>
inline  // 如果模板函数是内联函数,则inline的位置如下
T Sum(T& t1, T& t2)
{
    return t1 + t2;
}

template<int a, int b>  // 非类型模板参数
int Sum2()
{
    return a + b;
}

int main()
{
    int a = 1;
    int b = 2;
    int c1 = Sum(a, b);       // 模板参数的类型,有时候是根据你提供的数据类型推断出来的
    int c2 = Sum<int>(a, b);  // 也可显式指定模板的参数类型

    int d1 = Sum2<1, 2>();   // 非类型模板参数传值
    // 也就是说,模板<>中的值都是通过调用的时候<>中的值来赋值的
    int d2 = Sum2<a, 2>();   // 不可以,非类型模板参数,必须在编译的时候就给定值,
    // 所以里面传递的参数必须是常量,因为常量在定义的时候就会初始化好

    // 小结:模板<>中的值必须是在编译的时候就知道的,比如类型 T 要是明确地类型,int a要是确切的值
    system("pause");
    return 0;
}

// 函数模板小结:
// 模板定义不会导致编译器生成代码,只有在我们调用这个函数的时候
// 使编译器会为我们实例化一个特定版本的函数之后,编译器才会生成代码 // 函数模板的定义直接放在 .h 文件中,多个cpp include 不会出现重定义

二、类模板

 1、一般定义格式

template <class T1, class T2>
class MyVector
{
public:
    MyVector MyFun();
    void MyFun2() {
    // ...
    // 可以直接在类模板的定义中实现成员函数的定义,这样的函数被隐式声明为inline函数
    } 
};

template <class T1, class T2>    // 函数定义之前需要将模板的参数类型写在函数体前
MyVector<T1, T2> MyVector<T1, T2>::MyFun(){
    // ...
    // 声明在类模板定义之外,有多个模板参数,都要写在<>括号内
}

2、带非类型参数的定义格式

// 非类型模板参数
template <class T, int size = 10>
class MyArray
{
public:
    T arr[size];
    
    void Fun();
};

template <class T, int size = 10>
void MyArray<T, size>::Fun();
// 非类型模板参数的限制
// (1)浮点型参数不可以做非类型模板参数,float,double
// (2)类类型也不可以

3、成员函数模板

不管是普通类还是模板类,它的成员函数都可以是一个函数模板,称为成员模板函数

成员模板函数不可以是虚函数,否则编译器会报错

class Element
{
public:
    template <typename T>
    void fun(T t)
    {
        cout << t << std::endl;
    }
};

Element ele;
ele.fun(3);    // 编译器会根据这个数字来推断成员模板函数的类型

4、模板显示实例化,模板声明

主要作用:为了防止在多个.cpp 文件中都实例化相同的类模板

// 类模板的定义在一个.h 文件中  
template <T>
class Element;
// 在多个.cpp 文件中用到了这个类模板

template Element<int>; // 只需在一个 .cpp 文件中,写上这句话
// 实例化定义只有一个
// 这句的意思是显示地定义一个该类型的模板类

extern template Element<int>;  // 在其他 .cpp 文件中只需要声明模板类即可
// extern作用:不会在本文件中生成一个extern后面所表示的模板的实例化版本代码
// extern目的:告诉编译器,其他的源文件中已经有了一个该模板类的实例化版本
// 注意:显示实例化和模板类声明都是在 .cpp 文件中,而不是在 .h 文件中
// 函数模板也是同样的道理
template <T>
void fum(T t1, T t2);        // 定义函数模板的.h文件中

template void fum(int t1, int t2);   // 一个cpp文件中
extern template void fum(int t1, int t2); //其他用到该函数模板的cpp文件中

三、一些小知识点

1、函数指针作为其他函数的参数

// 函数指针作为类型参数的情况
typedef int(*FunType)(int, int);   // 定义一个函数指针的类型, FunType可以看做是一种类型

int Sum(int i, int j)
{
    return  i + j;
}

void testFun(int i, int j, FunType fun)
{
    int res = fun(i, j);   // 这里传递的这个fun 就是传进来的一个函数
}
// 上面的testFun函数用下面的模板函数,在main函数中的调用效果都是相同的
///////
template <typename T, typename F>
void testFun(const T& i, const T& j, F fun)
{
    cout<< fun(i, j) << endl;   // 这里传递的这个fun 就是传进来的一个函数
}
////////

int main()
{
    testFun(1, 2, Sum);   // 将函数名传递给一个函数作为参数
    return 0;
}

 2、默认 类模板参数 和 函数模板参数

// 假定的函数模板如下
template <typename T, typename F>
void testSum(const T& t1, const T& t2, F tempfun)
{
    cout << tempfun(t1, t2);
}
// 默认函数模板参数
typedef int(*pFun)(int, int);  //定义函数指针类型

int sumfun(int i, int j)   // 符合该函数指针类型的函数
{
    return i + j;
}

template <typename T, typename F = pFun>  // F表示一种函数指针类型
void testSum(const T& t1, const T& t2, F tempfun = sumfun) // 表示函数指针所表示的具体函数名
{
    cout << tempfun(t1, t2);
}
// 默认类模板参数
class Element
{
    int operator()(int i, int j) const
    {   // 重载圆括号运算符,此处并非构造函数
        // 重载圆括号运算符之后,该类的对象可以当做函数来使用
        return i + j;
    }
};

template <typename T, typename F = Element> // F表示的是一种类型
void testSum(const T& t1, const T& t2, F tempfun = Element())   // tempfun表示F类型的具体函数名
{
    cout << tempfun(t1, t2);
}

小结:

类模板的模板参数必须<>指定,成员函数模板或者普通函数模板的参数可以推断

3、using 定义模板别名

 

template<typename T>
using str_map = std::map<std::string, T>  // str_map 是类型别名

template<typename T>
struct{
    typedef std::map<std::string, T>  str_map ;  // typedef 定义一个类型别名,要放在一个结构体中
};

//  using用于定义类型的时候, 包括了typedef 的所有功能,

// using 和 typedef 定义的区别
typedef unsigned int m_int;
using m_int = unsigned int; 

typedef int(*pf)(int, int);
using pf= int(*)(int, int); 

str_map<string>  strmap;     
strmap.insert({"key", "value"});

 

 

 

 

posted @ 2020-06-16 23:52  min_zhi  阅读(255)  评论(0编辑  收藏  举报