(三)c++模板函数与函数模板详解

1、模板函数与函数模板的区别

模板函数:根据模板写出来的函数。

函数模板:以后函数实例化都是根据这个模板进行的。

#include <iostream>
using namespace std;

// T Max(T a, T b) 函数模板
template<typename T>
T Max(T a, T b)
{
        return a > b ? a : b;
}

int main()
{
        cout<<Max<int>('a', 8)<<endl;   // Max<int>('a', 8) 模板函数
        cout<<Max(7, 8)<<endl;  // Max(7, 8) 模板函数 
        return 0;
}

  

2、函数模板深入理解

(1)编译器从函数模板通过不同类型产生不同函数

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

  [1] 对模板代码本身进行编译

  [2] 对参数替换后的代码进行编译

(3)注意事项

  [1] 函数模板本身不允许隐式类型转换

  [2] 自动推导类型时,必须严格匹配

  [3] 显式类型指定时,能够进行隐式类型转换

#include <iostream>
using namespace std;

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

int main()
{
        cout<<Max(7, 8)<<endl; // 可自动推导类型为int
        cout<<Max<int>('a', 8)<<endl; // 两个参数的类型不同,不要隐式转换为int,因为函数模板不允许隐式转换
        return 0;
}

3、函数模板的本质

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

class Test
{
private:
        Test(const Test&) {}
public:
        Test() {}
};

template <typename T>
void Swap11(T& a, T &b)
{
        T c = a;
        a = b;
        b = c;
}

typedef void (FuncA) (int&, int&);
typedef void (FuncB) (double&, double&);
typedef void (FuncC) (Test&, Test&);

int main()
{
        /* 解析:
        FuncA * pa = Swap11; 
                编译器自动推导T为int
                用模板Swap11去出师Pa
                pa的类型又是 void (FuncA) (int&, int&);
                因此,编译器会用int去替换T,然后生成一个Swap函数
                并把指针赋值给pa
        FuncB * pb = Swap11;
                编译器自动推导T为double
        FuncC * pc = Swap11;
                编译器自动推导T为test,但是进行T替换时,
                由于Swap函数内部的T c = a; 
                会调用Test的拷贝构造函数Test(const Test&) {}
                但它是私有的,所以编译会出错
        */

        FuncA * pa = Swap11;
        FuncB * pb = Swap11;

        // 证明pa与pb是不同的两个函数
        cout<<"pa= "<<reinterpret_cast<void*>(pa)<<endl;
        cout<<"pb= "<<reinterpret_cast<void*>(pb)<<endl;

        //FuncC * pc = Swap11;
        //cout<<"pc= "<<reinterpret_cast<void*>(pc)<<endl;
        return 0;
}

  

4、函数模板多参数

特点:

【1】无法自动推导返回值类型;

【2】可以从左向右部分指定类型参数;

【3】工程中将返回值参数作为第一个类型参数

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

template <typename T1, typename T2, typename T3>
T1 Add(T2 a, T3 b)
{
        cout<<"T1= "<<a<<endl;
        cout<<"T2= "<<b<<endl;
        return static_cast<T1>(a);
}

int main()
{
        // T1 = <int> = int , T2 = 0.9 = double , T3 = 0.8 = double
        // <int> 从左向右指定类型(返回值->参数1->参数2) 未指定到的, 自动推导类型
        int a = Add<int>(0.9, 0.8);
        cout<<"返回结果为 "<<a<<endl;

        // T2 = <double> = double, T2 = 10 = int, T3 = 1.9 = double
        double b = Add<double, char>('b', 91.2);
        cout<<"返回结果为 "<<b<<endl;

        // T3 = <char> = char, T2 = 90 = int, T3 = 9.8 = float 
        char c = Add<char, int, float>(90, 9.8);
        cout<<"返回结果为 "<<c<<endl;
        return 0;
}

  

5、函数模板重载

【1】优先匹配普通函数,其次匹配函数模板

【2】如果函数模板可以产生一个更好的匹配,那么选择模板

【3】可以通过空模板实参列表,限定只匹配模板

  int a = Max(1,2);  // 优先匹配普通函数

  int b = Max<>(1,2);  // <>空模板实参列表,只能匹配函数模板

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

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

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

template <typename T>
T Max(T a, T b, T c)
{
        cout<<"---函数模板---"<<endl;
        return Max(Max(a, b), c);
}

int main()
{
        int a = 10;
        int b = 88;
        cout<<Max(a, b)<<"

";
        cout<<Max<>(a, b)<<"

"; // <>限定只能从函数模板去匹配
        cout<<Max(3.8, 4.1)<<"

";
        cout<<Max(3.8, 4.1, 8.8)<<"

"; // 参数个数匹配
        cout<<Max('u', 8.8)<<"

"; // 不允许隐式转换,所以不会匹配函数模板
        return 0;
}

6、总结

(1)函数模板通过具体类型产生不同的函数

(2)函数模板可以定义任意多个不同的类型参数

(3)函数模板中的返回值类型必须是显示指定

(4)函数模板可以像普通函数一样重载

参考自大神 https://www.cnblogs.com/5iedu/category/811805.html

做一个优秀的程序媛
原文地址:https://www.cnblogs.com/oytt/p/13852611.html