• 《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.

  • 相关阅读:
    ADF中遍历VO中的行数据(Iterator)
    程序中实现两个DataTable的Left Join效果(修改了,网上第二个DataTable为空,所处的异常)
    ArcGIS api for javascript——鼠标悬停时显示信息窗口
    ArcGIS api for javascript——查询,然后单击显示信息窗口
    ArcGIS api for javascript——查询,立刻打开信息窗口
    ArcGIS api for javascript——显示多个查询结果
    ArcGIS api for javascript——用图表显示查询结果
    ArcGIS api for javascript——查询没有地图的数据
    ArcGIS api for javascript——用第二个服务的范围设置地图范围
    ArcGIS api for javascript——显示地图属性
  • 原文地址:https://www.cnblogs.com/strinkbug/p/1347055.html
Copyright © 2020-2023  润新知