【C++深度解析】42、函数模板及其本质分析

文章目录

    • 1 函数模板
      • 1.1 函数模板的语法规则
      • 1.2 函数模板的使用
    • 2 函数模板的本质
    • 3 多参数函数模板
    • 4 函数模板遇见函数重载
    • 5 小结

对于函数体相同,仅仅参数类型不同的函数我们可以使用函数模板来解决,这是 C++ 中的一种泛型编程。

1 函数模板

函数模板是一种特殊的函数可用不同的类型进行调用,
【C++深度解析】42、函数模板及其本质分析_第1张图片

1.1 函数模板的语法规则

  • template 关键字用于声明开始进行泛型编程
  • typename 关键字用于声明泛型编程

【C++深度解析】42、函数模板及其本质分析_第2张图片

1.2 函数模板的使用

  • 自动类型推导调用
  • 具体类型显示调用

用法如下:
【C++深度解析】42、函数模板及其本质分析_第3张图片

编程实验:模板函数初探

// 42-1.cpp
#include
#include
using namespace std;
template<typename T>
void Swap(T& a, T& b)
{
    T c = a;
    a = b;
    b = c;
}
template<typename T>
void Sort(T a[], int len)
{
    for (int i = 0; i < len; i++)
    {
        for (int j = i; j < len; j++)
        {
            if (a[i] > a[j])
            {
                Swap(a[i], a[j]);
            }
        }
    }
}
template<typename T>
void print(T a[], int len)
{
    for (int i = 0; i < len; i++)
    {
        cout << a[i] << ", ";
    }
    cout << endl;
}
int main()
{
    int a[5] = {4, 5, 1, 3, 2};
    Sort(a, 5);
    print(a, 5);
    string s[5] = {"Java", "C++", "Go", "Python", "C"};
    Sort(s, 5);
    print(s, 5);
    return 0;
}
$ g++ 42-1.cpp -o 42-1
$ ./42-1
1, 2, 3, 4, 5, 
C, C++, Go, Java, Python, 

2 函数模板的本质

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

  • 对模板本身进行编译
  • 对参数替换后的代码进行编译

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

  • 自动推导类型时,必须严格匹配
  • 显示类型指定时,能够进行隐式类型转换

编程实验:函数模板的本质

// 42-2.cpp
#include
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定义函数类型
typedef void(FuncI)(int&, int&);
typedef void(FuncD)(double&, double&);
typedef void(FuncT)(Test&, Test&);
int main()
{
    FuncI* pi = Swap;
    FuncD* pd = Swap;
    //FuncT* pt = Swap;
    cout << "pi = " << reinterpret_cast<void*>(pi) << endl;
    cout << "pd = " << reinterpret_cast<void*>(pd) << endl;
    //cout << "pt = " << reinterpret_cast(pt) << endl;
    return 0;
}
  • 使用 typedef 定义三个函数类型,函数模板编译器要编译一次,参数替换后的代码还要编译一次。第 25,26 行,两个指针分别指向两个具体的函数。
  • 类 Test 中的拷贝构造函数定义为私有,但是在生成具体代码时,私有构造函数无法完成赋值,会编译出错。再次验证了编译器对模板本身要编译,对替换后的代码还要编译。

编译运行

$ g++ 42-2.cpp -o 42-2
$ ./42-2
pi = 0x55daa8490a01
pd = 0x55daa8490a2e

可以看到函数指针的地址不同。

3 多参数函数模板

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

【C++深度解析】42、函数模板及其本质分析_第4张图片
对于多参数函数模板

  • 无法自动推导返回值类型
  • 可以从左向右部分指定类型参数

【C++深度解析】42、函数模板及其本质分析_第5张图片
工程中将返回值参数作为第一个类型参数

编程实验:多参数函数模板

// 42-3.cpp
#include
using namespace std;
template<typename T1, typename T2, typename T3>
T1 add(T2 a, T3 b)
{
    return static_cast<T1>(a + b);
}
int main()
{
    int r1 = add<int>(0.5, 0.8);
    double r2 = add<double, float>(0.5, 0.8);
    float r3 = add<float, float, float>(0.5, 0.8);
    cout << "r1 = " << r1 << endl;
    cout << "r2 = " << r2 << endl;
    cout << "r3 = " << r3 << endl;
    return 0;
}
  • 使用第一个参数指定返回值类型,求解 r1 时,T1 为 int,T2 为 double,T3 为 double
  • 求解 r2 时,T1 为 double,T2 为 float,T3 为 double
  • 求解 r2 时,T1 为 float,T2 为 float,T3 为 float
$ g++ 42-3.cpp -o 42-3
$ ./42-3
r1 = 1
r2 = 1.3
r3 = 1.3

4 函数模板遇见函数重载

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

  • 优先考虑普通函数
  • 如果函数模板可以产生一个更好的匹配,则选择模板
  • 可以通过空模板实参列表限定编译器只匹配模板

【C++深度解析】42、函数模板及其本质分析_第6张图片

// 42-3.cpp
#include
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 << endl;			// 普通函数 MAX(int, int)
    cout << MAX<>(a, b) << endl << endl;		// 函数模板 MAX(int, int)
    cout << MAX(3.0, 4.0) << endl << endl;		// 函数模板 MAX(double, double)
    cout << MAX(5.0, 6.0, 7.0) << endl << endl;	// 函数模板 MAX(double, double, double)
    cout << MAX('a', 70) << endl << endl;		//  普通函数 MAX(int, int)
    return 0;
}

优先考虑普通函数;如果函数模板有更好的匹配,则选择模板;也可以通过空模板实参列表只匹配模板

编译运行

$ g++ 42-4.cpp -o 42-4
$ ./42-4
int MAX(int a, int b)
2

T MAX(T a, T b)
2

T MAX(T a, T b)
4

T MAX(T a, T b, T c)
T MAX(T a, T b)
T MAX(T a, T b)
7

int MAX(int a, int b)
97

5 小结

1、函数模板能够根据实参对参数类型进行推导
2、可以自动类型推导调用,也可以显示指定参数类型
3、函数模板通过具体类型产生不同的函数
4、寒素模板可以定义多个不同的类型参数
5、函数模板可以重载

你可能感兴趣的:(C++深度解析)