模板显式、隐式实例化和(偏)特化、具体化的详细分析

最近看了<The C++ Programing Language>看到了模板的特化,突然想起来<C++ Primer>上说的显式具体化、隐式具体化、特化、偏特化、具体化等概念弄得头晕脑胀,我在网上了找了好多帖子,才把概念给理清楚。

看着这么多叫法,其实就是三种:

  1. 显示实例化
  2. 隐式实例化
  3. 特化(=具体化)、偏特化

一、实例化

1.显示、隐式实例化

什么是实例化:一个通过使用具体值替换模板参数,从模板产生的普通类,函数或者成员函数的过程。

显示实例化:通过名字可见,就是清楚的表明你要实例化的类型

隐式实例化:通过编译器自己推测判断要实例化的类型。

比如一个模板:

template<class T> //函数模板实现
void swap(T &a, T &b)
{
   T temp;
   temp = a;
   a = b;
   b = temp;
}

a. 显示实例化

template void swap< int >(); // 无须给该函数重新编写函数体,这只是个声明

为什么要显示实例化?

主要是提高效率,当显式实例化模板时,在使用模板之前,编译器根据显式实例化指定的类型生成模板实例,这样就相当于本程序里面有个一

void swap(int &a, int &b)
{
   int temp;
   temp = a;
   a = b;
   b = temp;
}

这样的话,每次需要调用 swap(a,b)的时候每次都重新生成该类型的代码,可以节省空间,也能提高效率。这就是为什么要是显式的实例化的原因。

b. 隐式实例化

隐式实例化指的是:在使用模板之前,编译器不生成模板的声明和定义实例。只有当使用模板时,编译器才根据模板定义生成相应类型的实例。

int i=0, j=1;
swap(i, j); //编译器根据参数i,j的类型隐式地生成swap(int &a, int &b)的函数定义。

隐式实例化就是程序员为了省事,把类型省略让编译器判断,这是一个偷懒的表现吧。

二、特化

1. 特化(=具体化)

然而通常又有一些特殊的情况,不能直接使用泛型模板展开实现,这时就需要针对某个特殊的类型或者是某一类特殊的类型,而实现一个特例模板—-即模板特化

当T如果为 一个 struct类型的,它的交换就无法进行,所以我们针对这种特殊的情形,我们专门写了一个函数,只有当T为 这种struct类型时候,才会调用这个特化的函数

//对函数
#define MAXNAME 128
struct job
{
char name[MAXNAME]:
int salary;
};
 
template<class T>
void swap(T &a, T &b )
{
  T temp;
  temp = a;
  a = b;
  b = temp;
};
 
template void swap<int>(int &a, int & b);  //显式实例化,只需声明
 
template<> void swap<job>(job &a, job &b)   //显式具体化(上面已经讲过,注意与实例化区分开,必须有定义)
{
  int salary:
  salary = a.salary:
  a.salary = b.salary;
  b.salary = salary;
};//explicite specialization.
 
//对类模板:
template <class T>
class Arrary
{
private:
  T* ar;
  int l;
...
};//template class declaration.
 
template class Array<int>;   //explicit instantiation. 显式实例化
 
template<> class Array<job>
{
private:
  job* ar;
  int l;
};//expicit specialization.   显式具体化,类定义体可以不同于类模板Array

2. 偏特化

模板的偏特化是指需要根据模板的部分参数进行特化

a. 类模板的偏特化

  • 参数
    在这里插入图片描述

  • 范围
    -在这里插入图片描述

b. 函数模板的偏特化
网上看到有人说:从严格意义上讲,函数模板并不支持偏特化(我对这个不是很理解),但由于可以对函数进行重载,所以可以达到类似于类模板偏特化的效果。

比如:
a) template < class T > void f(T);
根据重载规则,对a)进行重载
b) template < class T> void f(T*);
如果将a)称为基模板,那么b)称为对基模板a)的重载,而非对a)的偏特化。
这里我就不深入的剖析偏特化了。

三、模板的匹配顺序

1. 类模板的匹配规则

例如:
template < class T > class vector{//…//}; // (a) 普通型
template class vector < typename > ; // (b) 的显式实例化
template < class T> class vector<T*>{//…//}; // © 对指针类型特化
template <> class vector <void*>{//…//}; // (d) 对void*进行特化

每个类型都可以用作普通型(a)的参数,但只有指针类型才能用作(b)的参数,而只有void*才能作为( c)的参数

所以,当一个调用一个模板类,首先,找显式实例化的,如果不匹配;接着,找特化的,然后,找偏特化的,最后,根据模板隐式实例化

2.函数模板的匹配规则

例如:

void swap(int &a, int &b){} // 普通的函数
template<> swap< int >(int &a, int &b){} // 特化的模板函数
template void swap< int >(int &a, int &b); // 显式实例化,这个只用声明就行
template< class T > void swap(T &a, T &b){} // 模板

以上书写的顺序就是模板的调用顺序。

<think>好的,我现在要解答用户关于C++特化实例化的区别的问题。首先,我需要先理解这两个概念各自的定义,然后找出它们之间的不同点。用户提供的几个引用内容应该能帮助我梳理清楚。 首先看实例化。根据引用4,实例化模板在使用具体类型创建实例的过程。例如,当有一个模板类DataAdd<T>,当用int替换T时,就实例化了DataAdd<int>。实例化分为两种。实例化是编译器根据代码中的使用自动生成,如用户调用Add(a,b)时,编译器自动生成对应的函数版本。而实例化则是在代码中明确指定类型,如template void f<int>(int);,这样编译器会在该处生成int版本的函数,避免多次实例化,节省编译时间,这在多文件项目中很有用(引用1中的例子)。 接下来是特化特化分为全特化特化。全特化是针对模板参数全部指定的情况,例如引用3中的Date<int, char>,它完全指定了模板参数,提供了特定类型的实现。而特化则是部分指定参数,例如针对指针类型或某个特定类型组合。特化的目的是为某些特定类型提供优化或不同的实现,而通用模板可能不适用这些情况。 现在需要区分实例化特化的不同。实例化是创建模板的具体类型实例,无论是还是,都是基于已有的模板代码生成具体代码。而特化是提供模板的一个特殊版本,当特定类型被使用时,编译器会优先选择特化版本而不是原模板。例如,当有全特化的Date<int, char>时,创建Date<int, char>对象时会调用特化版本的构造函数,而不是原模板的。 另一个区别在于,实例化是一个必须的过程,因为模板本身不能直接使用,必须实例化为具体类型。而特化是可选的,只有在需要为特定类型定制行为时才使用。例如,通用模板可能无法处理某些类型,或者需要优化性能,这时就需要特化。 还要注意实例化特化的语法区别。实例化使用template 后跟具体的类型,如template void f<int>(int);,而特化则使用template<>并指定参数,如template<> class Date<int, char> {};。 用户提供的引用2中提到了实例化时类型不匹配的处理,以及引用1中实例化在多文件编译中的应用,这可以帮助理解实例化的机制。而引用34则详细说明了特化的语法用途。 总结来说,实例化是生成具体类型代码的过程,而特化是为特定类型提供定制实现的模板版本。实例化是必须的步骤,而特化是可选的优化或定制手段。两者在语法应用场景上都有明区别。</think>### C++模板特化实例化的区别及联系 #### 1. **核心定义** - **实例化**:将模板转换为具体类型代码的过程,是模板使用的必经步骤。 - **实例化**:编译器根据调用自动推导类型生成代码,例如: ```cpp Add(1, 2); // 实例化Add<int> ``` - **实例化**:手动指定模板参数类型,强制生成特定代码: ```cpp template void f<int>(int); // 实例化int版本[^1] ``` *作用*:减少重复编译,优化多文件项目性能。 - **特化**:为特定类型提供定制化的模板实现,是模板的“特殊版本”。 - **全特化**:完全指定所有模板参数: ```cpp template<> class Date<int, char> { /*...*/ }; // 全特化版本[^3] ``` - **特化**:部分指定模板参数(如类型修饰或部分参数固定): ```cpp template<class T> class Data<T*> { /*...*/ }; // 针对指针类型的特化 ``` *作用*:优化特定类型的性能或处理特殊逻辑[^4]。 --- #### 2. **关键区别** | **维度** | **实例化** | **特化** | |----------------|-------------------------------|------------------------------| | **目的** | 生成具体类型代码 | 为特定类型提供定制实现 | | **必要性** | 必须(模板使用的前提) | 可选(仅在需要时定义) | | **语法形** | `template void f<int>(int);` | `template<> class C<int>{};` | | **多文件影响** | 实例化可避免重复编译 | 特化需在头文件中定义 | --- #### 3. **典型场景** 1. **实例化的必要性** 模板代码必须通过实例化才能生成可执行代码。例如: ```cpp DataAdd<int> obj; // 实例化模板类 obj.Add(1, 2); // 调用实例化后的函数[^4] ``` 2. **特化的应用场景** - 需要为`int`类型优化算法性能: ```cpp template<> void Sort<int>(int* arr) { /*快速排序实现*/ } ``` - 处理指针类型的特殊逻辑(特化): ```cpp template<class T> class Data<T*> { /*指针类型的特殊处理*/ }; ``` --- #### 4. **关联与注意事项** - **优先级规则**:特化版本优先于通用模板被调用。 - **实例化特化的冲突**:若对特化类型实例化,可能导致重复定义。 - **编译分离**:实例化常用于多文件编译,避免链接错误。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值