标准库学习中的基础知识(二)

类别:编程语言 点击:0 评论:0 推荐:

P298
       “对于大多数人,首先得和最明显的应用就是定义和使用容器类。”
       “在调用模板函数时,函数参数的类型决定了到底应该使用哪个版本,也就是说,模板的参数是由函数推断出来的。”
P299
        “对于一个调用,能从函数的参数推断出模板参数的能力是其中最关键的东西。”
        “编译器能从一个调用推断出类型参数和非类型参数,条件是:由这个调用的函数参数能够唯一的标识出模板参数的一个集合。
            例如:template<class T , int i>T& lookup(Butter<T,i>&b,const char*p);
            class Record
            {
                const char[2];
                //...
            };
            Record& f(Butter<Record,128>& buf,const char *p)
            {
                return lookup(buf,p); //使用lookup( ),其中T是Record , i是128
            }    //在这里推断出T是Record,i是128
         ”
        “注意,绝不会对类模板的参数做任何推断。”
        “如果不能从模板函数的参数推断出某个模板参数,我们就必须显示地去描述它。
            template<class T>class cector{/*...*/};
            template<class T>T* create( ); //创建一个T,返回到它的指针
            void f( )
            {
                    vector<int>v;    //类,模板参数“int”
                    int* p=create<int>( );    //函数,模板参数“int”
            }
          ”
P300
        *关于函数模板的重载
        “可以声明多个具有同样名字的函数模板,甚至可以声明具有同样一个名字的多个函数模板和常规函数组合。例如:
            template<class T>T sqrt(T);
            template<class T>complex<T> sqrt(complex<T>);
            double sqrt(double);
            void f(complex<double> z)
            {
                sqrt(2);    //sqrt<int>(int)
                sqrt(2.0);    //sqrt(double)
                sqrt(z);    //sqrt<double>(complex<double>)
            }”

        “简而言之,对每个模板,我们都要找出对这个组合函数参数的一组最基佳专门化结果。”
        “找出能参与这个重载解析的一组函数模板专门化。”
        “如果两个模板函数都可调用,其中一个比另一个更专门,在随后的步骤中就只考虑那个最专门的模板函数。”
        “在这组函数上重载解析,包括那些按照常规函数考虑也应该加上去的常规函数。”
        “如果一个函数和一个专门化具有同样好的匹配,那么就选用函数。”
        “找不到匹配,就是一个错误。”
P302
        “所以,任何一种通用的解决方案,都要求排序算法应当以某种通用的方式表述,使它的定义不但可以用于特定类型,而且还可以用于特定类型的特定应用。”
        
P303
        “每次调用都需要显示地给出比较准则也会使人厌烦。还好,很容易确定一种默认方式,这样,就只有那些不平常的比较准则才需要显式地给出。这可以通过重载来实现:
            template<class T,class C>
            int compare(const String<T>&str1,const String<T>&str2);    //用C比较
            
            template<class T>
            int compare(const String<T>&str1,const String<T>&str2);    //用Cmp<T>比较”
        “换一种方式,我们也可以将常规的习惯作为默认模板参数:
            template<class T,class C=Cmp<T> >    //注意:这里两个> >要有空格。
            int compare(const String<T>&str1,const String<T>&str2); ”
P305
        “对一个模板的这些可以相互替代的定义称为用户定义类型的专门化,或简称为用户专门化。”
        “专门化是一种针对一个共同界面,为不同的使用提供各种可替代的实现的方法。”
P306
        “说一个专门化比另一个更专门化,如果能够与它匹配的每个实际参数表也能与另外的那个专门化匹配,但反过来就不是。”
P308
        “从一个非模板类派生出一个模板类,这是为一组模板提供一个共用实现的方法。例如:template<class T>class Vector<T*>:private Vector<void *>{/*...*/}
P309
        “为了能有所区分,将虚函数提供的东西称作运行时多态性,而把模板提供的称为编译时多态性,或者参数式多态性。”
P310
        “如果在这些对象间并不需要某种层次性的关系,那么最好是将它们作为模板的参数。如果在编译时,无法确定这些对象的类型,那最好将它们表示为一个公共抽象类的许多派生类。”
P311
        “模板实现的是一种在需要时能够基于用户描述去生成类型的机制,正因为此,类模板有时也被称为类型生成器。”
P313
        “分开编译方式:
            //out.h
            template<class T>void out(const T& t);
            //out.c
            #include<iostream>
            #include“out.h”
            export template<class T>void out(const T&t){std::cerr<<t;}
            //user.c
            #include“out.h”
                //使用out( )
            为了使其他编译单位能够访问,就必须将这个模板定义显式地声明为export,...如果没有这样做,在任何地方要使用模板,都将要求它的定义必须位于作用域中。   


            

本文地址:http://com.8s8s.com/it/it24655.htm