zoukankan      html  css  js  c++  java
  • 《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.

  • 相关阅读:
    mybatis源码解读(二)——构建Configuration对象
    mybatis源码解读(一)——初始化环境
    JDK1.8源码(七)——java.util.HashMap 类
    JDK1.8源码(六)——java.util.LinkedList 类
    JDK1.8源码(五)——java.util.ArrayList 类
    JDK1.8源码(四)——java.util.Arrays 类
    JDK1.8源码(三)——java.lang.String 类
    JDK1.8源码(二)——java.lang.Integer 类
    JDK1.8源码(一)——java.lang.Object类
    Java的深拷贝和浅拷贝
  • 原文地址:https://www.cnblogs.com/strinkbug/p/1347055.html
Copyright © 2011-2022 走看看