c++的模板(一)函数模板

      注: 本文所有的示例都是在vs2013版本下测试的   

     模板:模板就是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型定义为参数,从而实现了真正的代码可重用性。

     模板分为两类,一个是函数模板,另一个是类模板。

  注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。  

 一 函数模板

     函数模板:代表了一个函数家族,该函数与类型无关,在使用的时候被参数化,根据实参类型产生函数的特定类型版本。

     函数模板的一般形式:

       Template <class或者也可以用typename T>  // 建议使用typename,但是不能用struct代替class

        返回类型 函数名(形参表)
        {//函数定义体 }

说明:1函数模板也可以定义为inline函数 ,inline关键字放在模板形参表之后,返回值之前,不能放在template之前

         举例:      

             template<typename T>
             inline T Add(const T _left, const T _right)
            {
		return (_left + _right);
	     }
           2模板编译了两次,第一次实例化之前,检查模板代码本身,查看是否出现语法错误,如:遗漏分号;

           第二次:在实例化期间,检查模板代码,查看是否所有的调用都有效,如:实例化类型不支持某些函数的调用。

        3类型形参转换

             编译器只会执行种转换:(1)const转换:接收const引用或者const指针的函数可以分别用非const对象的引用或者指针来调用

如:template<const int *a> class A{}; int b; A<&b> m;   即从int *到const int *的转换。

(2)数组或函数到指针的转换:如果模板形参不是引用类型,则对数组或函数类型的实参应用常规指针转换。

数组实参将当做指向其第一个元素的指针,函数实参当做指向函数类型的指针.

如:template <int *a> class A{}; int b[1]; A<b> m;

模板形参:类型形参

1模板形参名字只能在模板形参之后模板声明或定义的末尾之间使用,遵循名字屏蔽规则

	typedef int T;  //作用域全局
	template<typename T> //形参T的作用域为该函数模板
	void FunTest(T t)
	{
		cout << "t type :" << typeid(t).name() << endl;
	}//模板函数形参作用域结束

	T gloab;
	int main()
	{
	FunTest('a');// 输出char
	cout << "gloab type:" << typeid(T).name() << endl;//输出int
	system("pause");
	return 0;
	}

2 模板形参的名字在同一模板形参列表中只能使用一次

         template<typename T,typename T>
//error:重定义模板参数"T"
void FunTest(T t1, T t2)
{
}

  3所有模板形参前面必须加上class或typename修饰

template<class T, U, typename V>
void f1(T, U, V);
// 无法识别标示符U

          4 函数模板可以指定缺省的模板实参 vs2013版本下

           template<typename T, typename T2 = int >                           template<typename T, typename T2 >  
   void FunTest1(T t1, T2 t2)                                                          void FunTest1(T t1, T2 = int  t2);
  {
  cout << t2 << endl;
           }

        5模板形参列表不能为空

6模板类型形参可作为类型说明符用在模板中的任何地方,与内置类型或自定义类型使用方法完全相同,可用于指定函数形参类型、返回值、局部  变量和强制类型转换。

模板形参:非类型形参   

        1非类型模板形参:模板的非类型形参也就是内置类型形参

       2非类型形参在模板定义的内部是常量值,也就是说非类型形参在模板的内部是常量。

        3非类型模板的形参只能是整型,指针和引用,像double,String, String **这样的类型是不允许的。但是double &,double *,对象的引 用或指针是正确的。

4调用非类型模板形参的实参必须是一个常量表达式,即他必须能在编译时计算出结果。

5注意:任何局部对象,局部变量,局部对象的地址,局部变量的地址都不是一个常量表达式,都不能用作非类型模板形参的实参。全局指针类型,全局变量,全局对象也不是一个常量表达式,不能用作非类型模板形参的实参。

6全局变量的地址或引用,全局对象的地址或引用const类型变量是常量表达式,可以用作非类型模板形参的实参

7当模板的形参是整型时调用该模板时的实参必须是整型的,且在编译期间是常量,比如template <class T, int a> class A{};如果有intb,这时A<int, b> m;将出错,因为b不是常量,如果const int b,这时A<int, b> m;就是正确的,因为这时b是常量。

8非类型形参一般不应用于函数模板中,比如有函数模板template<class T, int a> void h(T b){},若使用h(2)调用会出现无法为非类型形参a推演出参数的错误,对这种模板函数可以用显示模板实参来解决,如用h<int, 3>(2)这样就把非类型形参a设置为整数3。

函数模板的重载

1一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。
2、对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调动非模板函数而不会从该模板产生出一个实例。
 

     如果模板可以产生一个具有更好匹配的函数,那么将选择模板。
3、显式指定一个空的模板实参列表,该语法告诉编译器只有模板才能来匹配这个调用,而且所有的模板参数都应该根据实参演绎出
4、模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。
   

int Max(const int& left, const int & right)
{
	return left>right ? left : right;
}

template<typename T>
T Max(const T& left, const T& right)
{
	return left>right ? left : right;
}
template<typename T>
T Max(const T& a, const T& b, const T& c)
{
	return Max(Max(a, b), c);
};
int main()
{
	Max(10, 20, 30);//调用第三个
	Max<>(10, 20); //调用第二个
	Max(10, 20);   // 调用第一个
	Max(10, 20.12); //调用第一个,发生隐式类型转换
	Max<int>(10.0, 20.0); // 显示声明 调用第二个
	Max(10.0, 20.0); //调用第二个 两个参数都不是int类型 只能调用函数模板生成一个
	system("pause");
	return 0;
}
 函数模板特化

 模板函数特化形式如下:

template<>
返回值 函数名<Type>(参数列表)
{
// 函数体
}

注意:1特化的声明必须与特定的模板相匹配 

    2 在模板特化版本的调用中,实参类型必须与特化版本函数的形参类型完全匹配,
     如果不匹配,编译器将为实参模板定义中实例化一个实例。 

        3 特化不能出现在模板实例的调用之后,应该在头文件中包含模板特化的声明,

  然后使用该特化版本的每个源文件包含该头文件。

    

template<typename T>
int compare(T t1, T t2)
{
	if (t1 < t2) return -1;
	if (t1 > t2) return 1;
	return 0;
}
template<>
int compare<const char *>(const char*  p1, const char*  p2)
{
	return strcmp(p1,p2);
}
int main()
{
	const char *pStr1 = "1234";
	const char *pStr2 = "abcd";
	char *pStr3 = "1234";
	char *pStr4 = "abcd";
	cout << compare(pStr1, pStr2) << endl; //调用特化
	cout << compare(pStr3, pStr4) << endl; //调用模板函数
	system("pause");
	return 0;
}

        


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值