zoukankan      html  css  js  c++  java
  • 《c++ templates》学习笔记(8)——第十一章 模板实参演绎

     

    1       第十一章 模板实参演绎

    1.1    演绎的过程

    每个实参-参数对的分析都是独立的;因此,如果最后得出的结果是矛盾的,那么演绎的过程将失败。

    我们来看个例子:

    template<typename T>

    typename T::ElementT at(T const& a, int i)

    {

         return a[i];

    }

     

     

    void g1(int* p)

    {

         int x = at(p, 2);

    }

     

    void g2(int* p)

    {

         int x = at<int*>(p, 2);

    }

    在上面的例子中,g1g2都会报错,但是错误的信息会有所不同。

    g1报错是因为演绎失败,g2报错是因为指定的类型是个无效类型。S

    下面给出实参-参数匹配的规则:匹配类型A(来自实参的类型)和参数化类型P(来自参数的声明)。如果被声明的参数是一个引用声明(即T&),那么P就是所引用的类型(即T),而A仍然是实参的类型。否则的话,P就是所声明的参数类型,而A则是实参的类型;如果这个实参的类型是数组或者函数类型,那么还会发生decay转型,转换为对应的指针类型,同时还会ihulue高层次的constvolatile限定符

     

    这里要记住的一点是:引用参数是不会进行decay的。

    1.2    节接受的实参转型

    在找不到匹配实参的时候,有一些转型是允许的;

    l         从有const volatile限定符到没有;

    l         从没有限定符到有constvolatile限定符;

    l         当演绎的类型不涉及到转型运算符的时候,被替换的P类型可以是A类型的基类;或者当A是指针类型时,P可以是一个指针类型,它所指向的类型是A所指向的类型的基类。

    这里要重点说明一下第三点。例如:

    template<typename T>

    class B{

    public:

         virtual void f(){

             std::cout<<"B::f()"<<std::endl;

         }

    };

     

    template<typename T>

    class D: public B<T>{

    public:

         virtual void f(){

             std::cout<<"D::f()"<<std::endl;

         }

    };

     

    template<typename T>

    void f(B<T>* b)

    {

         b->f();

    }

    template<typename T>

    void f(B<T> b)

    {

         b.f();

    }

    int _tmain(int argc, _TCHAR* argv[])

    {

         D<int> d;

         f(&d);//1, void f(B<T>* b)

         f(d); //2, void f(B<T> b)

         return 0;

    }

    在上面的例子中,2值得我们关注,这种传值的方式也可以实现子类到基类的匹配还是想出不来的,不过这里经过验证是如此,我们只需记住就好。

    如果对f再加上下面这个重载。

     

    template<typename T>

    void f(D<T> d)

    {

         d.f();

    }

    那么,在上面的2处调用的就是这个版本,而不是void f(B<T> b)版。

    原来我以为上面的规则是模板适用,经过实验发现,其实是通用的:

    class BB{};

     

    class DD:public BB{};

     

    void f(BB b)

    {

         std::cout<<"void f(BB b)"<<std::endl;

    }

    int _tmain(int argc, _TCHAR* argv[])

    {

         DD dd;

         f(dd);//调用的是void f(BB b)

         return 0;

    }

    但是如果将上面的代码改为:

    class BB{};

     

    class DD:public BB{};

     

    template<typename T>

    void f(T a)

    {

         std::cout<<"void f(T a)"<<std::endl;

    }

     

    void f(BB b)

    {

         std::cout<<"void f(BB b)"<<std::endl;

    }

    int _tmain(int argc, _TCHAR* argv[])

    {

         DD dd;

         f(dd);//调用的是void f(T a)

         return 0;

    }

    此处调用的就是模板,这说明,只有在是在找不到匹配的类型时,c++编译器才会去转型以适应参数调用。

    1.3    缺省实参调用

    对于缺省调用实参而言,及时不是依赖型的,也不能用于演绎模板实参。来看例子:

    template<typename T>

    void h(T x = 42)

    {}

    int _tmain(int argc, _TCHAR* argv[])

    {

         h<int>();//ok

         h(); //error,42不能用来演绎T

         return 0;

    }

  • 相关阅读:
    centos6.5 系统乱码解决 i18n --摘自http://blog.csdn.net/yangkai_hudong/article/details/19033393
    openssl pem转cer
    nginx 重装添加http_ssl_module模块
    ios 利用airprint实现无线打印(配合普通打印机)
    centos nginx server_name 配置域名访问规则
    MySQL Innodb数据库性能实践——热点数据性能
    jQuery中的DOM操作
    C++函数学习笔记
    jQuery选择器容易忽视的小知识大问题
    写给自己的话
  • 原文地址:https://www.cnblogs.com/strinkbug/p/1342699.html
Copyright © 2011-2022 走看看