C/C++普通函数与函数模板的区别,调用规则,模板局限性

简介: C/C++普通函数与函数模板的区别,调用规则,模板局限性

普通函数与函数模板的区别

普通函数与函数模板区别:

  • 普通函数调用时可以发生自动类型转换(隐式类型转换)
  • 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
  • 如果利用显示指定类型的方式,可以发生隐式类型转换

示例:

//普通函数

intmyAdd01(inta, intb)

{

   returna+b;

}

//函数模板

template<classT>

TmyAdd02(Ta, Tb)  

{

   returna+b;

}

//使用函数模板时,如果用自动类型推导,不会发生自动类型转换,即隐式类型转换

voidtest01()

{

   inta=10;

   intb=20;

   charc='c';

   

   cout<<myAdd01(a, c) <<endl; //正确,将char类型的'c'隐式转换为int类型  'c' 对应 ASCII码 99

   //myAdd02(a, c); // 报错,使用自动类型推导时,不会发生隐式类型转换

   myAdd02<int>(a, c); //正确,如果用显示指定类型,可以发生隐式类型转换

}

intmain() {

   test01();

   system("pause");

   return0;

}

总结:建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型T

普通函数与函数模板的调用规则

调用规则如下:

  1. 如果函数模板和普通函数都可以实现,优先调用普通函数
  2. 可以通过空模板参数列表来强制调用函数模板
  3. 函数模板也可以发生重载
  4. 如果函数模板可以产生更好的匹配,优先调用函数模板

示例:

//普通函数与函数模板调用规则

voidmyPrint(inta, intb)

{

   cout<<"调用的普通函数"<<endl;

}

template<typenameT>

voidmyPrint(Ta, Tb)

{

   cout<<"调用的模板"<<endl;

}

voidtest01()

{

   //1、如果函数模板和普通函数都可以实现,优先调用普通函数

   // 注意 如果告诉编译器  普通函数是有的,但只是声明没有实现,或者不在当前文件内实现,就会报错找不到

   inta=10;

   intb=20;

   myPrint(a, b); //调用普通函数

   

   //2、可以通过空模板参数列表来强制调用函数模板

   myPrint<>(a, b); //调用函数模板

}

intmain() {

   test01();

   system("pause");

   return0;

}

//普通函数与函数模板调用规则

voidmyPrint(inta, intb)

{

   cout<<"调用的普通函数"<<endl;

}

template<typenameT>

voidmyPrint(Ta, Tb)

{

   cout<<"调用的模板"<<endl;

}

template<typenameT>

voidmyPrint(Ta, Tb, Tc)

{

   cout<<"调用重载的模板"<<endl;

}

voidtest01()

{

   //3、函数模板也可以发生重载

   intc=30;

   myPrint(a, b, c); //调用重载的函数模板

   //4、 如果函数模板可以产生更好的匹配,优先调用函数模板

   charc1='a';

   charc2='b';

   myPrint(c1, c2); //调用函数模板

}

intmain() {

   test01();

   system("pause");

   return0;

}

分析:如果函数模板可以产生更好的匹配,优先调用函数模板

以上面案例为例,编译器默认调用了普通函数,发现还需要把char转成int,又发现如果调用模板则只需确定类型即可,于是调用模板函数,最优选择。

总结:既然提供了函数模板,最好就不要提供普通函数,否则容易出现二义性

模板的局限性

局限性:

  • 模板的通用性并不是万能的

例如:

   template<classT>

   voidf(Ta, Tb)

   {

       a=b;

   }

在上述代码中提供的赋值操作,如果传入的a和b是一个数组,就无法实现了

再例如:

   template<classT>

   voidf(Ta, Tb)

   {

       if(a>b) { ... }

   }

在上述代码中,如果T的数据类型传入的是像Person这样的自定义数据类型,也无法正常运行

因此C++为了解决这种问题,提供模板的重载,可以为这些特定的类型提供具体化的模板

示例:

#include<iostream>

usingnamespacestd;

#include <string>

classPerson

{

public:

   Person(stringname, intage)

   {

       this->m_Name=name;

       this->m_Age=age;

   }

   stringm_Name;

   intm_Age;

};

//普通函数模板

template<classT>

boolmyCompare(T&a, T&b)

{

   if (a==b)

   {

       returntrue;

   }

   else

   {

       returnfalse;

   }

}

//第一种方法:重载算术运算符==,缺点:太麻烦

//第二种方法:

//具体化,显示具体化的原型和定意思以template<>开头,并通过名称来指出类型

//具体化优先于常规模板

template<>boolmyCompare(Person&p1, Person&p2)

{

   if ( p1.m_Name  ==p2.m_Name&&p1.m_Age==p2.m_Age)

   {

       returntrue;

   }

   else

   {

       returnfalse;

   }

}

voidtest01()

{

   inta=10;

   intb=20;

   //内置数据类型可以直接使用通用的函数模板

   boolret=myCompare(a, b);

   if (ret)

   {

       cout<<"a == b "<<endl;

   }

   else

   {

       cout<<"a != b "<<endl;

   }

}

voidtest02()

{

   Personp1("Tom", 10);

   Personp2("Tom", 10);

   //自定义数据类型,不会调用普通的函数模板

   //可以创建具体化的Person数据类型的模板,用于特殊处理这个类型

   boolret=myCompare(p1, p2);

   if (ret)

   {

       cout<<"p1 == p2 "<<endl;

   }

   else

   {

       cout<<"p1 != p2 "<<endl;

   }

}

intmain() {

   test01();

   test02();

   system("pause");

   return0;

}

总结:

  • 利用具体化的模板,可以解决自定义类型的通用化
  • 学习模板并不是为了写模板,而是在STL能够运用系统提供的模板
目录
相关文章
|
7天前
|
存储 算法 搜索推荐
【C++】类的默认成员函数
【C++】类的默认成员函数
|
7天前
|
编译器 C++
【C++】模板初级
【C++】模板初级
|
7天前
|
安全 编译器 C++
【C++】模板进阶
【C++】模板进阶
|
12天前
|
存储 编译器 C语言
C++内存管理(区别C语言)深度对比
C++内存管理(区别C语言)深度对比
41 5
|
5天前
|
Dart 编译器 API
Dart ffi 使用问题之在C++线程中无法直接调用Dart函数的问题如何解决
Dart ffi 使用问题之在C++线程中无法直接调用Dart函数的问题如何解决
|
27天前
|
Web App开发 Rust 分布式计算
Rust与C++的区别及使用问题之对于大量使用C++实现的产品来说,迁移到Rust的问题如何解决
Rust与C++的区别及使用问题之对于大量使用C++实现的产品来说,迁移到Rust的问题如何解决
|
27天前
|
Rust 安全 编译器
Rust与C++的区别及使用问题之Rust中的bound check对性能产生影响的问题如何解决
Rust与C++的区别及使用问题之Rust中的bound check对性能产生影响的问题如何解决
|
27天前
|
Rust 测试技术 编译器
Rust与C++的区别及使用问题之Rust项目中组织目录结构的问题如何解决
Rust与C++的区别及使用问题之Rust项目中组织目录结构的问题如何解决
|
11天前
|
JavaScript C++
【C++ visual studio】解决VS报错:error C2447: “{”: 缺少函数标题(是否是老式的形式表?)【亲测有效,无效捶我】
【C++ visual studio】解决VS报错:error C2447: “{”: 缺少函数标题(是否是老式的形式表?)【亲测有效,无效捶我】
|
11天前
|
缓存 C++ Windows
Inno setup 脚本判断 Microsoft Visual C++ Redistributable 不同版本区别
Inno setup 脚本判断 Microsoft Visual C++ Redistributable 不同版本区别