【C/C++】【模板和泛型】模板概念和函数模板的定义及使用

概述

  • 泛型编程,是以独立于任何特定类型的方式编写代码,使用泛型编程时,需要提供具体程序实例所操作的类习惯或者值;

  • 模板是泛型编程的基础,模板是创建类或者函数的蓝图或者公式,给这些蓝图或者公式足够的信息,让这些蓝图或者公式真正的转变为具体的类或者函数,这种转换发生在编译时;

  • 模板支持将类型作为参数的程序设计方式,从而实现了对泛型程序设计的直接支持;

  • 泛型编程中,编译时就能获知类型

  • 容器/迭代器/算法都是泛型编程的例子,独立于任何特定类型来编写代码

  • 模板一般分为函数模板和类模板;

模板定义

  • 模板定义用template关键字开头,后面跟<>,<>里面叫模板参数列表(模板实参);

  • 如果模板参数列表中有多个参数,则用逗号分开;<>里必须至少有一个模板参数;

  • 模板参数里面有个typename/class关键字;

  • 模板参数列表中表示在函数定义中用到的 "类型" 或者 "值" 也和函数列表类似;可以指定模板实参;

  • 模板函数可以是inline的,inline的位置放在模板参数列表之后

  • 模板的定义不会导致编译器生成代码,只有在我们调用这个函数模板时,编译器实例化了一个特定版本的函数之后,才会生成代码;

  • 编译器生成代码的时候,需要能够找到函数的函数体,所以函数模板的定义通常是在.h文件中。

//求a + b的函数模板
//T实际是类型,编译器在编译的时候回针对add函数模板的调用来确定;
template<typename T>
T add(T a, T b)
{
    T sum = a + b;
    return sum;
}


template<typename T>
inline
T sub(T a, T b)
{
    T ans= a - b;
    return ans;
}

函数模板的使用

  • 调用方式与普通函数相同
  • 调用的时候,编译器会根据调用这个函数模板的实参去推断模板参数列表里的参数(形参)的类型
  • 编译器在推断出来这个模板的形参类型之后,编译器实例化一个特定版本的函数
//求a + b的函数模板
//T实际是类型,编译器在编译的时候回针对add函数模板的调用来确定;
template<typename T>
T add(T a, T b)
{
    T sum = a + b;
    return sum;
}

int main()
{
    int x = add(3, 1);
    //double y = add(3, 1.1); //出错,系统不知道推断成int还是double
}

非类型模板参数

  • 模板参数列表中也可以定义非类型参数
  • 非类型参数代表一个值;不能用typename和class来修饰;
  • 当模板被实例化的时候,这种非类型模板参数的值是程序员提供的或者编译器推断的;这些值必须用常量表达式,因为实例化这些模板是编译器在编译的时候来实例化的;
//非类型模板参数 特例
template<int a, int b>
int func_add()
{
	return a + b;
}

int main()
{
	int x = func_add<3, 1>(); //显示的指定模板参数
    int a = 1;
	//int y = func_add<a, 1>(); //报错,值必须是在编译时候就可以确定;必须是常量表达式;
	cout << x << endl;
	return 0;
}

template<typename T, int a, int b>
int func_add_three(T c)
{
   return a + b + (int)c;
}


int main()
{
   int x = func_add_three<int, 3, 1>(13);

   int y = func_add_three<double, 3, 1>(13);//系统以T类型为准,而不是根据实参13的值

   cout << x << endl;
   cout << y << endl;
   return 0;
}
//不提供 非类型模板参数 的情况  系统自己推断
template<unsigned l1, unsigned l2>
int my_strcmp(const char (&p1)[l1], const char (&p2)[l2])
{
	return strcmp(p1, p2);
}

int main()
{
	int res = my_strcmp("test", "test"); //没有提供 非类型模板参数,系统会根据字符串长度,取代l1和l2
	cout << res << endl;
	return 0;
}

总结

  • 函数模板和重载的区别
  • 如何定义函数模板
  • 函数模板是何时被实例化的
  • 类型模板参数 和 非类型模板参数
posted @ 2020-08-03 09:31  NaughtyCoder  阅读(384)  评论(0)    收藏  举报