函数模板、重载的模板、显式具体化、实例化和具体化

本文介绍了C++中的模板功能,包括如何定义和使用函数模板,以及模板的重载。通过示例展示了如何交换不同类型的数据,以及如何为特定类型如`job`结构体实现显式具体化。此外,还讨论了模板的隐式实例化、显示实例化和显示具体化之间的区别,并给出了相关代码示例。

part 1

函数模板(p281)是通用的函数描述,它们使用泛型来定义函数,其中的泛型可用具体的类型(如int/double)替换。通过将类型作为参数传递给模板,可使编译器生成该类型的函数。

可以建立这样一个交换模板:

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

Note:1、建立一个模板,并将类型名命名为T;关键字typename可用class代替;必须使用尖括号,没有分号。

2、声明和定义时不能只写void Swap(T &a,T &b)还要加上template语句

3、模板并不创建任何函数,而只是告诉编译器如何定义函数。需要交换int的函数时,编译器将按模板模式创建这样的函数,并用int代替T。

#include<iostream>
template <typename T>
void Swap(T &a,T &b);


int main()
{
    char a = 'o',b = 'k';
    Swap(a,b);
    std::cout << a << std::endl << b;

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

最终的代码不包含任何模板,而只包含了为程序生成的实际函数。使用模板的好处是,它使生成多个函数定义更简单、更可靠。

part 2

重载的模板

可以像重载常规函数定义那样重载模板定义,被重载的模板的函数特征标必须不同。

#include<iostream>

template <typename T>
void Swap(T &a,T &b);
template <typename T>
void Swap(T a[],T b[],int n);

template<typename T>
void show(T a[],int n = 5);

int main()
{
    char a = 'o',b = 'k';
    Swap(a,b);
    std::cout << a << std::endl << b << std::endl;

    int arr1[10] = {1,2,3,4,5,6,7,8,9,10};
    int arr2[10] = {10,9,8,7,6,5,4,3,2,1};
    Swap(arr1,arr2,10);
    show(arr1,10);
    show(arr2,10);

    char s1[] = "cqupt";
    char s2[] = "xupts";
    Swap(s1,s2,5);
    show(s1,5);
    show(s2,5);
}

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

template <typename T>
void Swap(T a[],T b[],int n)
{
    T temp;
    for (int i = 0;i < n;i++)
    {
        temp = a[i];
        a[i] = b[i];
        b[i] = temp;
    }
}

template<typename T>
void show(T a[],int n )
{
    using namespace std;
    for(int i = 0;i < n;i++)
        cout << a[i] << ",";
    std::cout << std::endl;
}

part3

模板的局限性:编写的模板可能无法处理某些类型。

显式具体化:假设定义了如下结构。

struct job
{
    /* data */
    char name[40];
    double salary;
    int floor;
};

c++运行将一个结构赋给另一个结构,我们只想交换salary和floor成员,而不交换name成员。

然而,可以提供一个具体化函数定义——称为显示具体化,其中包含所需的代码。当编译器找到与函数调用匹配的具体化定义时,将使用该定义,而不再寻找模板。

第三代具体化(ISO/ANSI C++标准)

对于给定的函数名,可以有非模板函数、模板函数、显式具体化模板函数以及它们的重载版本。

显示具体化的原型和定义应以template<>打头,并通过名称来指出类型。

具体化优于常规函数,而非模板函数优于具体化和常规函数。

template<>void Swap<job>(job &j1,job &j2);

其中<job>是可选的,也就是可以去掉。

示例:

#include<iostream>

struct job
{
    /* data */
    char name[40];
    double salary;
    int floor;
};

template <typename T>
void Swap(T &a,T &b);
template<>void Swap<job>(job &j1,job &j2);
void show(job &a);

int main()
{
    job staff1 = {"jack",2333.3,6};
    job staff2 = {"vic",9000,9};
    Swap(staff1,staff2);
    show(staff1);
    show(staff2);
    
}

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

template<>void Swap<job>(job &j1,job &j2)
{
    double s;
    int f;
    s = j1.salary;
    j1.salary = j2.salary;
    j2.salary = s;
    f = j1.floor;
    j1.floor = j2.floor;
    j2.floor = f;
}

void show(job &a)
{
    std::cout << a.name << ": " << a.salary
    << " RMB " << a.floor << "floor(s)\n";
}

part4

实例化和具体化

记住,代码中包含函数模板本身并不会生成函数定义,他只是一个用于生成函数定义的方案。

上述代码中Swap(i,j);导致编译器生成Swap()的一个实例,该实例使用int类型。模板并非函数定义,但使用int的模板实例是函数定义,这种实例化方法被称为隐式实例化

C++还允许显式实例化,这意味着可以直接命令编译器创建特定的实例,其语法是,声明所需的种类——用<>符号指示类型,并在声明前加上关键字template:

template void Swap<int>(int,int);

该声明的意思是”使用Swap()模板生成int类型的函数定义“

与显式实例化不同,显式具体化使用下面两个等价的声明之一

template<>void Swap<int>(int &,int &);
template<>void Swap(int &,int &);

这些声明的意思是”不要使用Swap()模板来生成函数定义,而应使用专门为int类型显式地定义的函数定义。“这些原型必须有自己的函数定义。

隐式实例化、显示实例化和显示具体化统称为具体化。它们的相同之处在于,它们表示的都是使用具体类型的函数定义,而不是通用描述。

疑惑?下面代码为啥报错

#include<iostream>
template<typename T>
T add(T &a,T &b);

template double add<double>(double,double);//显示定义一个形参为double的函数定义
                                            //,为什么报错
int main()
{
    double a = 11.5;double b = 11;
    //std::cout << add<double>(a,b);
    std::cout << add(a,b);

}

template<typename T>
T add(T &a,T &b)
{
    return a+b;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值