《c++ templates》学习笔记(11)——第十章 实例化

 

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)处,也就是f1POI处,编译器又进行了一次普通查找和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.

 

posted @ 2008-12-03 21:23  拿走不谢  阅读(1069)  评论(0编辑  收藏  举报