函数模板基础

本章知识点:(不按顺序讲解)

  1. 模板的类型参数
  2. 模板的非类型参数
  3. 模板的实参推演
  4. 模板函数的重载
以上为本文讲解的内容
  1. 模板的特例化(专用化)
    https://blog.csdn.net/KingOfMyHeart/article/details/98503430
  2. 模板的实例化:显式实例化 和 隐式实例化
    https://blog.csdn.net/KingOfMyHeart/article/details/98481514

1.模板的类型参数:

定义模板参数列表:
template <typename T,class E>  //类型由typename或者class指定;

T 和 E是类型参数,将来专门接收各种各样的类型.

2.函数模板与模板函数:
2.1 函数模板:即函数的模板;

//这是一个函数模板
template <typename T>
 bool compare(T a,T b)
 {
     sdssds
     cout<<typeid(T).name()<<endl;
     cout<<typeid(a).name()<<endl;                                                                                     
     cout<<typeid(b).name()<<endl;
     return a > b;
 }
 int main()
 {
 	return 0;
 }
 上述代码中,我在windows上进行编译,可以编译通过
 在g++下编译不通过,主要原因:

程序在编译的时候 windows下VS编译器只会检查函数模板的原型是都正确,而不会去检查函数体是都正确(windows下,linux下会检测出错:未定义的"sdssds").

模板原型:
template <typename T>
bool compare(T a,T b)

2.2 模板函数:通过函数模板实例化出的特定类型的函数代码

template <typename T>
 bool compare(T a,T b)
 {
	 //sdssds
     cout<<typeid(T).name()<<endl;
     cout<<typeid(a).name()<<endl;                                                                                     
     cout<<typeid(b).name()<<endl;
     return a > b;
 }
 int main()
 {
 	compare(100,200);
 	compare<double>(99.9,88.0);
 	compare<int>(77,666);
 	return 0;
 }

compare(100,200):在调用点调用时会生成下面这样一份代码,其中类型推导为int.

bool compare(int a,int b)
 {
	 //sdssds
     cout<<typeid(T).name()<<endl;
     cout<<typeid(a).name()<<endl;                                                                                     
     cout<<typeid(b).name()<<endl;
     return a > b;
 }
语法上来讲,编译器编译时实际上对上面生成的这份代码进行编译
想一下,如果我们不把sdssds这些未定义的字符串进行注释,在windows上编译可以通过吗?
bool compare(int a,int b)
 {
	 sdssds
     cout<<typeid(T).name()<<endl;
     cout<<typeid(a).name()<<endl;                                                                                     
     cout<<typeid(b).name()<<endl;
     return a > b;
 }

compare< double >(99.9,88.0):同样的也会生成一份代码,其中类型是调用者指定的double.
相当于将double传递给我们模板的参数列表中的T.

bool compare(double a,double b)
 {
	 //sdssds
     cout<<typeid(T).name()<<endl;
     cout<<typeid(a).name()<<endl;                                                                                     
     cout<<typeid(b).name()<<endl;
     return a > b;
 }

compare< int >(77,666):此时不会再生成int型的函数代码,因为上面已经有一份了.

3.模板的实参推演:

template <typename T>
 bool compare(T a,T b)
 {
     cout<<typeid(T).name()<<endl;
     cout<<typeid(a).name()<<endl;                                                                                     
     cout<<typeid(b).name()<<endl;
     return a > b;
 }
 int main()
 {
 	compare(100,200);
 	return 0;
 }

在上述代码中,我们在实例化函数时,并没有指定具体的类型,但是编译并没有出错
这是因为编译器会根据我们实际传递的实参的类型推导出来了一份int类型的代码
这个过程我们称为模板实参推演.

但是,实际上并不推荐大家使用编译器的实参推演,因为有的时候会出错
当实参中没有参数类型怎么办; 

case 1:

temlate<typename T>
T fun()
{
	T a;
	return a;
}
上面说过,编译器生成什么类型的代码的时候是根据调用点的 类型参数决定的
但是此时调用的时: fun();  
这样并没有给模板参数列表中的T进行赋值,也没有实参的传递,这样编译器就没法推导出究竟是什么类型.
1.cc:13:6: error: no matching function for call to ‘fun()’
  fun();
      ^
1.cc:6:3: note: candidate: template<class T> T fun()
 T fun()
   ^
1.cc:6:3: note:   template argument deduction/substitution failed:
1.cc:13:6: note:   couldn't deduce template parameter ‘T’
  fun();




case 2 :

temlate<typename T>
T fun(int a,int b)
{
	T a;
	return a;
}

即使你给该模板传递了两个实参,但是这个两个实参与类型T没有半毛钱的关系
编译器依然推导不出来.
1.cc: In function ‘int main()’:
1.cc:13:12: error: no matching function for call to ‘fun(int, int)’
  fun(100,99);
            ^
1.cc:6:3: note: candidate: template<class T> T fun(int, int)
 T fun(int a,int b)
   ^
1.cc:6:3: note:   template argument deduction/substitution failed:
1.cc:13:12: note:   couldn't deduce template parameter ‘T’
  fun(100,99);




case 3:

template <typename T>
 bool compare(T a,T b)
 {
     cout<<typeid(T).name()<<endl;
     cout<<typeid(a).name()<<endl;
     cout<<typeid(b).name()<<endl;
     return a > b;
 }

 int main()
 {
     compare(100,220.0);
     return 0;
 }
第一个参数是int,第二个参数是浮点型,可是我们模板的参数列表中只有一个
这样就产生二义性了,T == int  还是T == double呢.

deduced conflicting types for parameter ‘T’ (‘int’ and ‘double’)
compare(100,220.0);


除非增加一种模板类型参数
 template <typename T,typename E>
 bool compare(T a,E b)
 {
     //sdssds
     cout<<typeid(T).name()<<endl;    //int
     cout<<typeid(a).name()<<endl;   //int
     cout<<typeid(b).name()<<endl;   //double
     return a > b;
 }
实例化时:
compare<int>(100,99.9);  //此时 T==int  E== double

综上所述,我们还是多敲几个代码,老老实实的将需要实例化的类型传递给模板.

4.模板的"重载":

#include <iostream>
using namespace std;

template <typename T>
bool compare(T a,T b)
{
	cout<<"template<typename T>"<<endl;
	return a > b;
}

//模板的特例话
template<>
bool compare<int>(int a,int b)
{
	cout<<"template<> function"<<endl;
	return a>b;
}

//普通函数
bool compare(int a,int b)
{
	cout<<"nomal function"<<endl;
	return a>b;
}

int main()
{
	int a =10;
	int b = 100;
	compare(a,b);//不指定参数列表
	return 0;
}
输出:
nomal function

我们发现模板,模板的特例化以及普通的函数可以共存,调用时的优先顺序如下:

  1. 普通函数最优先:因为最轻量,不需要实例化代码;
  2. 其次是特例化函数;
  3. 最后才考虑根据函数模板去实例化一份代码.

严格意义上这不叫重载,因为重载一般指的是同一作用域下,函数名相同参数列表不同的函数,所以我在这里加个双引号.

5.模板的非类型参数:

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

//template<typename T,int SIZE = 99>  可以给一个默认值
template<typename T,int SIZE>
void mysort(T array[])
{
	int i = 0;
	int j = 0;
	T temp = T();       //零初始化  零构造
	for (i = 0; i<SIZE-1;++i){
		for(j= 0;j<SIZE-i-1;++j){
			if(array[j] > array[j+1])
			{
				temp = array[j];
				array[j] = array[j+1];
				array[j+1] = temp; 
			}
		}
	}
}
int main()
{
	int array[10];
	for (int i = 0; i < 10;++i)
	{
		array[i] = rand()%100+1;
	}
	
	mysort<int,10>(array);
	//调用的时候SIZE当做模板的非类型参数而不是函数的参数
	//这就是函数的非类型参数
	
	for (int i = 0; i < 10;++i)
	{
		cout<<array[i]<<" ";
	}
	cout<<endl;
	return 0;
}

非类型参数的特点:

  1. 模板非类型参数本身就是常量,所以我们使用的时候不能去修改它的值;
  2. 模板非类型参数可以在参数列表中给定一个默认值;
  3. 当然我们不能用变量给模板费类型参数传值;
  4. 不能用浮点数作为非类型参数,整数类型以及整数类型的指针和引用是可以的.
错误实例:
int size = 100;
mysort<int,size>(array); //size是个变量

const int size = 100;//这样就是OK的

总结几点:

  • 函数模板不编译,只有函数模板被实例化生成一份模板函数代码时,编译器才会去编译这份刚生成的代码;
  • 模板节省的是开发者写的代码,但是不会节省编译器编译的代码;
  • 模板本身是不可以被调用的,我们调用的是实例化以后的模板函数.
发布了237 篇原创文章 · 获赞 98 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/KingOfMyHeart/article/details/98479600