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

这么多叫法,其实就是三种。

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<int>(a,b)的时候每次都重新生成该类型的代码,可以节省空间,也能提高效率。这就是为什么要是显式的实例化的原因。

b. 隐式实例化

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

int i=0, j=1;
   swap(i, j); //编译器根据参数i,j的类型隐式地生成swap<int>(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. 类模板的偏特化

例如c++标准库中的类vector的定义

template <class T, class Allocator>
class vector { // … // };  
template <class Allocator>
class vector<bool, Allocator> { //…//};  
//这个偏特化的例子中,一个参数被绑定到bool类型,而另一个参数仍需要由用户使用时指定。

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*>{//…//}; // (c) 对指针类型特化
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){} // 模板

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

时间: 2024-10-14 17:27:32

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

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

这么多叫法,其实就是三种.      1. 显示实例化      2. 隐式实例化      3. 特化(=具体化).偏特化 一.实例化 1.显示.隐式实例化       什么是实例化:一个通过使用具体值替换模板参数,从模板产生的普通类,函数或者成员函数的过程.      显示实例化:通过名字可见,就是清楚的表明你要实例化的类型      隐式实例化:通过编译器自己推测判断要实例化的类型.     比如一个模板: template<class T> //函数模板实现  void swap(T

Android开发:显式/隐式Intent意图跳转Activity总结

显式跳转 在已知包名和类名的情况下常用的跳转方法: 是 nt mIntent = new Intent(); mIn Int etent.setClassName("com.android.settings","com.android.settings.Settings"); mContext.startActivity(mIntent); 我们也常这么用: y.class); startActivity(intent); 这是跳转到当前应用的某个Activity,

5. C# -- 显式/隐式类型转换,溢出检查

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 {     class Program {         static void Main(string[] args) {             ushort destinationVar;      

C++模板之隐式实例化、显示实例化、隐式调用、显示调用和模板特化详解

代码编译运行环境:VS2012+Debug+Win32 模板的实例化指函数模板(类模板)生成模板函数(模板类)的过程.对于函数模板而言,模板实例化之后,会生成一个真正的函数.而类模板经过实例化之后,只是完成了类的定义,模板类的成员函数需要到调用时才会被初始化.模板的实例化分为隐式实例化和显示实例化. 对函数模板的使用而言,分为两种调用方式,一种是显示模板实参调用(显示调用),一种是隐式模板实参调用(隐式调用).对于类模板的使用而言,没有隐式模板实参和显式模板实参使用的说法,因为类模板的使用必须显

(转载)Android理解:显式和隐式Intent

Intent分两种:显式(Explicit intent)和隐式(Implicit intent). 一.显式(设置Component) 显式,即直接指定需要打开的activity对应的类. 以下多种方式都是一样的,实际上都是设置Component直接指定Activity类的显式Intent,由MainActivity跳转到SecondActivity: 1.构造方法传入Component,最常用的方式 Intent intent = new Intent(this, SecondActivit

android中的显式与隐式Intent

Intent是Android初学者比较难理解的一个东西.我这里以通俗易懂的语言和通俗易懂的代码,让初学者简单感受一下Intent. intent就是意图的意思.Intent分两种:显式(Explicit intent)和隐式(Implicit intent). 一.显式(设置Component) 显式,即直接指定需要打开的activity对应的类.以下多种方式都是一样的,实际上都是设置Component直接指定Activity类的显式Intent,由MainActivity跳转到SecondAc

【转】Android理解:显式和隐式Intent---- try catch

原文网址:http://blog.csdn.net/xiao__gui/article/details/11392987 Intent是Android初学者比较难理解的一个东西.我这里以通俗易懂的语言和通俗易懂的代码,让初学者简单感受一下Intent. intent就是意图的意思.Intent分两种:显式(Explicit intent)和隐式(Implicit intent). 一.显式(设置Component) 显式,即直接指定需要打开的activity对应的类.以下多种方式都是一样的,实际

读书笔记 effective c++ Item 41 理解隐式接口和编译期多态

1. 显示接口和运行时多态 面向对象编程的世界围绕着显式接口和运行时多态.举个例子,考虑下面的类(无意义的类), 1 class Widget { 2 public: 3 Widget(); 4 virtual ~Widget(); 5 6 virtual std::size_t size() const; 7 virtual void normalize(); 8 9 void swap(Widget& other); // see Item 25 10 11 ... 12 13 }; 考虑下

C++模板编程里的主版本模板类、全特化、偏特化(C++ Type Traits)

1.  主版本模板类 首先我们来看一段初学者都能看懂,应用了模板的程序: 1 #include <iostream> 2 using namespace std; 3 4 template<class T1, class T2> 5 class A{ 6 public: 7 void function(T1 value1, T2 value2){ 8 cout<<"value1 = "<<value1<<endl; 9 cou