五十七课 深入理解函数模板

上一节我们对函数模板有了具体的了解,这节我们在深入的了解一下函数模板

一、函数模板的本质

     1、编译器从函数模板通过具体类型产生不同的函数

     2、 编译器会对函数模板进行两次编译

  •  对模板代码本身进行编译
  •   对参数替换后的代码进行编译(即调用时)

 示例:函数模板的本质

#include <iostream>

using namespace std;

class Test
{
     Test(const Test&);
public:
    Test()
    {
    }
};
template<typename T>
void Swap(T& a,T& b)
{
  T c = a;
  a = b;
  b = c;
}

typedef void (FuncI)(int&,int&);
typedef void (FuncD)(double&,double&);
typedef void (FuncT)(Test&,Test&);

int main()
{
 FuncI* pi = Swap;  //编译器自动推导T为int
 FuncD* pd = Swap;  //编译器自动推导T为double
 //FuncT* pt = Swap;  //编译器自动推导T为Test,如果加上这行代码会错。因为拷贝构造函数是私有的
                     // 在这里就能体现出编译器的二次编译
 
 cout << "pi = " << reinterpret_cast<void*>(pi) << endl;
 cout << "pd = " << reinterpret_cast<void*>(pd) << endl;
 //cout << "pt = " << reinterpret_cast<void*>(pt) << endl;
 
   return 0;
}

打印结果

通过打印指针的地址我们就可以看到这是两个不同的函数。

二、多参数函数模板

1、函数模板可以定义任意多个不同的类型参数

template
<typename T1,typename T2,typename T3>
T1 add(T2 a,T3 b)
{
   return static_cast<T1>(a+b);
}

2、对于多参数模板

(1)无法自动推导返回值类型

(2)可以从左到右部分指定类型参数

//T1=int T2=double T3=double
int r1 = add<int>(0.5,0.8);
//T1=int T2=float T3=double
int r2 = add<int,float>(0.5,0.8);
//T1=int T2=float T3=float
int r3 = add<int,float,float>(0.5,0.8);

在工程中如果返回值为泛指类型,我们就将返回值参数作为第一个类型参数,推荐第一种写法。

示例:多参数函数模板

#include <iostream>

using namespace std;

template
<typename T1,typename T2,typename T3>
T1 add(T2 a,T3 b)
{
   return static_cast<T1>(a+b);
}

int main()
{
 //T1=int T2=double T3=double
 int r1 = add<int>(0.5,0.8);

 //T1=double T2=float T3=double
 double r2 = add<double,float>(0.5,0.8);

 //T1=float T2=float T3=float
 float r3 = add<float,float,float>(0.5,0.8);
 
 cout << "r1 =" << r1 << endl;
 cout << "r2 =" << r2 << endl;
 cout << "r3 =" << r3 << endl;
 
   return 0;
}

打印结果

这个示例告诉我们工程中一定要将返回值参数作为第一个类型参数

三、有趣的问题

当函数重载遇见函数模板会发生什么?

函数模板可以像普通函数一样被重载

  • C++编译器会优先考虑普通函数
  • 如果函数模板可以产生一个更好的匹配,那么选择模板
  • 可以通过空模板实参列表限定编译器只匹配模板
int r1 = Max(1,2);
double r2 = Max<>(0.5,0.8); //限定编译器只选择模板

示例:重载函数模板

#include <iostream>
#include <string>

using namespace std;


template < typename T >
T Max(T a, T b)
{
    cout << "T Max(T a, T b)" << endl;
    
    return a > b ? a : b;
}

int Max(int a, int b)
{
    cout << "int Max(int a, int b)" << endl;
    
    return a > b ? a : b;
}

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

int main()
{
    int a = 1;
    int b = 2;
    
    cout << Max(a, b) << endl;                   // 普通函数 Max(int, int)
    
    cout << Max<>(a, b) << endl;                 // 函数模板 Max<int>(int, int)
    
    cout << Max(3.0, 4.0) << endl;               // 函数模板 Max<double>(double, double)
    
    cout << Max(5.0, 6.0, 7.0) << endl;          // 函数模板 Max<double>(double, double, double)
    
    cout << Max('a', 100) << endl;               // 普通函数 Max(int, int)
    
    return 0;
}

注意:函数模板本身不允许隐示类型转换

小结

  1. 函数模板通过具体类型产生不同的函数
  2. 函数模板可以定义任意多个不同的类型参数
  3. 函数模板的返回值类型必须显示指定
  4. 函数模板可以向普通函数一样被重载

猜你喜欢

转载自blog.csdn.net/qq_34862658/article/details/81808557