C++ Templates:实例化

延迟实例化:
当隐式实例化类模板时,同时也实例化了该模板的每个成员声明,但并没有实例化相应的定义,然而,存在例外:
1.如果类模板包含了一个匿名的union,那么该union定义的成员同时也被实例化了
2.作为实例化类模板的结果,虚函数的定义可能被实例化,但也可能没有,这依赖于具体实现

C++的实例化模型:
两阶段查找:
第1阶段:发生在模板的解析阶段
非依赖型名称:普通查找+ADL
非受限的依赖型名称:普通查找

第2阶段:发生在模板的实例化阶段,此时发生的地点称为一个实例化点POI
依赖受限名称:普通查找+ADL
非受限的依赖型名称:ADL (查询完后,和第1阶段的查找结果合并成为候选函数集合)

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

对于指向非类型特化的引用,C++把它的POI定义在“包含这个引用的定义或声明后的最近名字空间域”。
对于指向产生自模板的类实例的引用,它的POI只能定义在“包含这个实例引用的定义或声明之前的最近名字空间域”。

基本类型int没有关联名字空间,因此对其不会发生ADL查找。

例:

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。

分离模型导致跨翻译单元的重载二义性的例子:
//comm.cpp
export template <typename T>
void f(T);

class A { };
class B { };

class X {
public:
    operator A() { return A(); }
    operator B() { return B(); }
};

//a.cpp
#include "comm.cpp"
void g(A) { }
int main() {
    f<X>(X());
}

//b.cpp
#include "comm.cpp"
void g(B) { }

export template <typename T>
void f(T x) {
    g(x);
}
main()函数调用了f<X>(X()),该模板中调用g(x)会基于X类型的实参进行实例化,函数g()会执行两次查找:一次使用普通查 找规则在b.cpp中进行(解析模板阶段),另一次是在a.cpp中使用ADL进行查找(实例化阶段)。第1次查找会找到g(B),第2次查找则找到了 g(A)。存在了二义性。

对包含模型的几种实现方案:
贪婪实例化:特定的实体可以在多个目标文件和程序库中多次出现,于是,编译器会使用某种方法对这些实体进行标记。当链接器找到多个实例的时候,它会保留其中一个实例,而抛弃所有其他的实例。这就是贪婪实例化的主要处理方式。
贪婪实例化的缺点:编译器会在生成和优化N个实例化体上浪费时间,而最后只有一个实例化体会被保留;链接器通常不会检查两个实例化体是否一样的;最后生成的所有目标文件的大小总和可能会很大,因为相同代码可能会生成多次。
贪婪实例化的优势:保留了源对象之间的原始依赖性。

询问实例化
迭代实例化

显式实例化:
从语法上讲,显式实例化指示符由关键字template和后面的特化声明组成,所声明的特化就是即将由实例化获得的特化。
在同一个程序中,每个特定的模板特化最多只能存在一处显式实例化,而且,如果某个模板特化已经被显式实例化了,就不能对它进行显式特殊化。
提高创建效率的一种方法是:在某一个位置手工实例化特定的模板特化,并且禁止在所有其他的翻译单元中进行模板的实例化。
在显式实例化指示符的前面,添加一个关键字extern,并且指出,只有不具备这个关键字的情况下,才会引发实例化过程。
例:
//翻译单元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();
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值