1 第十章 实例化
1.1 On-Demand实例化
有时又被称作隐式实例化,或者自动实例化。
1.2 延迟实例化
1.3 C++中的实例化模型
1.3.1 两阶段查找
当对模板进行解析的时候,编译器并不能解析依赖型名称,于是,编译器会在POI再次查找这些依赖型名称。另一方面,非依赖型名称在首次看到模板的时候就进行查找,因此在第一次查找时就可以诊断错误信息。于是就有了两阶段查找:第一阶段发生在模板的解析阶段;第二阶段发生在模板的实例化阶段。
1.3.2 POI=point of instantiation
对于非类型特化的引用,c++把他的POI定义在“包含这个引用的定义或申明之后的最近名字空间域”中。来看下面的例子:其f<int>的实例化点位于4处。
//10.3.2
class MyInt{
public:
MyInt(int i):mem(i){};
public:
int GetMem()const{ return mem;};
private:
int mem;
};
MyInt operator - (MyInt const& i){
return MyInt(-i.GetMem());
}
bool operator >(MyInt const& a, MyInt const& b){
return a.GetMem()>b.GetMem();
}
template<typename T>
void f(T i)
{
if(i>0)
g(-i);
}
//1
void g(MyInt)
{
//2
f<int>(42);
//3
}
//4
对于产生自模板的类实例化体的引用,他的POI只能定义在“包含这个实例引用的定义或者声明之前的最近名字空间域”,也就是下面代码的位置5。
template<typename T>
class S{
public:
T m;
};
//5
unsigned long h()
{
//6
return (unsigned long)sizeof(S<int>);
//7
}
//8
1.3.3 例子
template<typename T>
void f1(T x)
{
std::cout<<"void f1(T x)"<<std::endl;
g1(x);//(1)
}
void g1(int)
{
std::cout<<"void g1(int)"<<std::endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
//chapter10
f1(7);
//(2)
return 0;
}
按照c++标准,上面的代码将会产生编译错误,因为在f1中找不到g1,因为g1(int)的参数是int型,int型是没有关联名字空间和关联类的,所以不会进行ADL查找。
但是我在vs2005上验证之后发现,上面的代码是能够编译成功,也能够正确的执行。没有任何错误。我想这主要是因为在(2)处,也就是f1的POI处,编译器又进行了一次普通查找和ADL查找,在这里由于是int型,所以只需进行普通查找即可。
如果把上面的f1改为下面这样,则vs2005就会报错:
//template<typename T>
//void f1(T x)
void f1(int x)
{
std::cout<<"void f1(T x)"<<std::endl;
g1(x);//(1)
}
这是因为f1不再是模板,所以就没有了POI,那么在编译到f1定义时就要求见到g1的声明,但是看不到,所以报错。
如果我们把例子再改为:
template<typename T>
void f1(T x)
{
std::cout<<"void f1(T x)"<<std::endl;
g1(x);//(1)
}
namespace X{
class Inner{};
void g1(Inner)
{
std::cout<<"void g1(Inner)"<<std::endl;
}
void g1(int){
std::cout<<"void g1(int)"<<std::endl;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
//chapter10
X::Inner inner;
f1(inner);//(3)
//(2)
f1(7); //(4)
return 0;
}
在上面的(3)处不会报错,但是在(4)处会报错。这可能也充分说明了,在VS2005中,在POI处,确实会进行一次普通查找,然后也会进行一次ADL。
1.4 显式实例化
注意:这里说的是显示实例化,而不是显示特化。
对于某个模板来说,他最多只能被显式实例化一次。而且如果该模板已经被显式特化了,则他不能再进行显式实例化。例如:
template<typename T>
class S{
};
template<>
class S<int>{};
template class S<int>;
上面的代码在编译的时候就会报错:'S<int>' : cannot explicitly instantiate an explicit specialization.