您的位置:首页 > 编程语言 > C语言/C++

C++模板实例化

2014-03-19 16:50 281 查看
实例化:一个通过使用具体值替换模板参数,从模板产生的普通类,函数或者成员函数的过程。

特化:就是上述过程最终获得实体。

延迟实例化:

当隐式实例化类模板时,同时也实例化了该模板的每个成员声明,但并没有实例化相应的定义,然而,存在例外:

1.如果类模板包含了一个匿名的union,那么该union定义的成员同时也被实例化了

2.作为实例化类模板的结果,虚函数的定义可能被实例化,但也可能没有,这依赖于具体实现

C++的实例化模型:

两阶段查找:

第1阶段:发生在模板的解析阶段

非依赖型名称:普通查找+ADL

非受限的依赖型名称:普通查找,但它的查找是不完整的,在实例化的时候,还会再次进行查找。

 

第2阶段:发生在模板的实例化阶段,此时发生的地点称为一个实例化点POI

依赖受限名称:普通查找+ADL

非受限的依赖型名称:ADL (查询完后,和第1阶段的查找结果合并成为候选函数集合)

实例化地点POI:
当某些代码构造引用了模板特化,而且为了生成这个完整的特化,需要实例化相应模板的定义时,就会在源代码中产生一个实例化点(POI)。POI是位于源代码中的一个点,在该点会插入替换后的模板实例。

[cpp]
view plaincopy

class MyInt  
{  
public:  
    MyInt(int i);  
};  
  
MyInt operator - (const MyInt& );  
bool operator > (const MyInt&,const MyInt&);  
  
typedef MyInt Int;  
  
template <typename T>  
void f(T i)  
{  
    if(i > 0)  
        g(-i);  
}  
  
//(1)  
void g(Int)  
{  
    //(2)  
    f<Int>(32);  //调用点  
    //(3)  
}  
//(4)  

当C++编译器看到f<Int>(32)时,它知道要用MyInt来替换T来实例化模板,即生成了一个POI。(2)和(3)处,C++并不允许把::f<Int>(Int)的定义在这里插入。(1)和(4)的区别在于:在(1)处g(Int)是不可见的,所以在(4)处。

C++规定:对于指向非类型特化的引用,它的POI定义在“包含这个引用的定义或声明后的最近名字空间域”。

 

对于类的特化有点不同,例如:

[c-sharp]
view plaincopy

template <typename T>  
class S  
{  
public:  
    T m;  
};  
  
//(5)  
unsigned long h()  
{  
    //(6)  
    return ((unsigned long) sizeof(S<int>));  
    //(7)  
}  
//(8)  

当C++编译器看到S<int>时,它知道要用int来替换T来实例化模板,即生成了一个POI。(6)和(7)处,C++并不允许把的定义在这里插入。如果在(8)处,sizeof(S<int>)表达式是无效的,因为要编译到(8)只有才能知道S<int>的大小,而sizeof(S<int>)在(8)之前。C++规定:对于指向产生自模板的类实例的引用,它的POI定义在“包含这个实例引用的定义或声明之前的最近名字空间域”。

 

在实例化模板的时候,可能还需要进行某些附带的实例化。

[cpp]
view plaincopy

template <typename T>  
class S {  
public:  
    typename int I;  
};  
//(1)  
template <typename T>  
void f() {  
    S<char>::I var1 = 41;  
    typename S<T>::I var2 = 42;  
}  
int main() {  
    f<double>();  
}  
//(2):(2a)(2b)  

对于非类型实体,这种二次POI的位置和主POI的位置相同。

对于类型实体,二次POI的位置位于主POI位置的紧前处。

对于上例中,(1)处是S<char>的POI,(2a)是S<double>的POI,(2b)是f<double>的POI。

显式实例化:

从语法上讲,显式实例化指示符由关键字template和后面的特化声明组成,所声明的特化就是即将由实例化获得的特化。

在同一个程序中,每个特定的模板特化最多只能存在一处显式实例化,而且,如果某个模板特化已经被显式实例化了,就不能对它进行显式特殊化。

提高创建效率的一种方法是:在某一个位置手工实例化特定的模板特化,并且禁止在所有其他的翻译单元中进行模板的实例化。

在显式实例化指示符的前面,添加一个关键字extern,并且指出,只有不具备这个关键字的情况下,才会引发实例化过程。

例:

[cpp]
view plaincopy

//翻译单元1  
template <typename T>  
void f() { }  
extern template void f<int> ();   //声明但没有定义  
void g() {  
    f<int>();  
}  
//翻译单元2  
template <typename T>   
void f() { }  
template void f<int>();       //手工实例化,这是实例化  
void g();  
int main() {  
    g();  
}  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息