C++ 函数模板 实例化和具体化

本文深入探讨了C++中的函数模板概念,包括其实例化(显式与隐式)及具象化的应用方法。通过具体示例展示了如何根据不同类型的需求进行函数定义,以提高代码复用性和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

函数模板是C++新增的一种性质,它允许只定义一次函数的实现,即可使用不同类型的参数来调用该函数。这样做可以减小代码的书写的复杂度,同时也便于修改。但是,在代码中包含函数模板本身并不会生成函数定义,它只是一个用于生成函数定义的方案。编译器使用模板为特定类型生成函数定义时,得到的是模板实例(instantiation)。


1 实例化

实例化有两种形式,分别为显式实例化和隐式实例化。模板并非函数定义,实例式函数定义。

1.1 显式实例化(explicit instantiation)

显式实例化意味着可以直接命令编译器创建特定的实例,有两种显式声明的方式。

比如存在这么一个模板函数

template <typename T>
void Swap(T &a, T &b)

第一种方式是声明所需的种类,用<>符号来指示类型,并在声明前加上关键词template,如下:
template void Swap<int>(int &, int &);

第二种方式是直接在程序中使用函数创建,如下:

Swap<int>(a,b);

显式实例化直接使用了具体的函数定义,而不是让程序去自动判断。

1.2 隐式实例化(implicit instantiation)

隐式实例化比较简单,就是最正常的调用,Swap(a,b),直接导致程序生成一个Swap()的实例,该实例使用的类型即参数a和b的类型,编译器根据参数来定义函数实例。


2 具象化(显式)

思考这么一个问题,当前的Swap模板交换输入的两个对象,可能式基本类型也可能式自定义类。如果有这么一个需求,需要交换自定义类里的某一个属性而不是整个类,那么Swap模板就不可用,因为Swap模板交换的是整个类。
显式具体化将不会使用Swap()模板来生成函数定义,而应使用专门为该特定类型显式定义的函数类型。有两种定义形式,如下,其中job为用户自定义类
template <> void Swap(job &a, job &b)
template <> void Swap<job>(job &a, job &b)
显式具体化在声明后,必须要有具体的实现,这是与显示实例化不同的地方。

3 举例

下面通过一个程序来观察实例化和具体化,加深理解。
/*************************************************************************
	> File Name: array.cpp
	> Author: 
	> Mail: 
	> Created Time: Sat 05 Aug 2017 01:20:31 AM PDT
 ************************************************************************/

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

struct job
{
    string name;
    int salary;
    job(string _name,int _salary):name(_name),salary(_salary){};
};

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

//explict specialization for job 显式具体化
template <> void Swap(job &a, job &b)
{
    int temp;
    temp = a.salary;
    a.salary = b.salary;
    b.salary = temp;
}

template void Swap<int>(int &, int &);
int main()
{
    char a = 'a', b = 'b';
    cout<<"a: "<<a<<" ; b: "<<b<<endl;
    Swap(a,b);  //1 implicit template instantiation for char 隐式实例化
    cout<<"a: "<<a<<" ; b: "<<b<<endl;

    int c = 1, d = 2;
    cout<<"c: "<<c<<" ; d: "<<d<<endl;
    Swap(c,d);  //2 use explicit template instantiation for int 显式实例化
    cout<<"c: "<<c<<" ; d: "<<d<<endl;
   
    Swap<int>(c,d);  //3 use explict template instantiation for int 显式实例化
    cout<<"c: "<<c<<" ; d: "<<d<<endl;
    
    job e("lucy",100), f("bob",200);
    cout<<"lucy: "<<e.name<<" "<<e.salary<<" ; bob: "<<f.name<<" "<<f.salary<<endl;
    Swap(e,f);  //use explict specialization for job 调用显式具体化
    cout<<"lucy: "<<e.name<<" "<<e.salary<<" ; bob: "<<f.name<<" "<<f.salary<<endl;
}

输出
➜  cpptest ./a.out      
a: a ; b: b
a: b ; b: a
c: 1 ; d: 2
c: 2 ; d: 1
c: 1 ; d: 2
lucy: lucy 100 ; bob: bob 200
lucy: lucy 200 ; bob: bob 100

备注:隐式实例化和显式实例化和显式具体化统称为具体化,它们的相同在于都用了具体类型的函数定义,而不是通用描述。
### C++ 函数模板的显式实例化C++中,为了实现函数模板的显式实例化,可以在 `template` 关键字之后紧跟函数声明(而非定义),并附带具体的模板参数。这种方式允许程序员提前告知编译器哪些类型的模板实例将会被使用,从而优化链接过程中的对象文件生成[^2]。 对于给定的例子而言: ```cpp #include <iostream> using namespace std; // 定义一个通用版本的A函数模板 template<class T> T A(T a, T b) { T c = a - b; cout << "普通模板函数" << c << endl; return c; } // 显式实例化的声明部分应该放在源文件外部或者头文件内部 template int A<int>(int a, int b); ``` 上述代码展示了如何对外部使用的特定类型(int型)执行显式实例化操作。需要注意的是,实际的函数体仍然保持不变,只是增加了针对该类型的单独声明语句来触发编译期间的具体化处理。 当涉及到类成员函数模板时,情况略有不同。无论是普通的类还是模板类,都可以拥有作为其一部分存在的成员函数模板。然而,这些成员函数模板不允许是虚函数。一旦编译器遇到了调用此类成员函数的地方,它会自动尝试创建相应的实例[^3]。 至于更复杂的场景——即嵌套于其他模板结构之内的函数模板,则需遵循一定的规则来进行特化或实例化工作。特别是当涉及跨多个翻译单元共享相同逻辑的需求时,合理运用显式实例化能够有效减少重复编译带来的开销,并有助于管理大型项目中的依赖关系[^4]。 #### 注意事项 - 对于全局作用域下的简单函数模板来说,只需要提供一次性的显式实例化声明即可满足需求。 - 如果是在类的作用范围内,则可能还需要考虑访问权限以及友元声明等因素的影响。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值