《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;

}

原文地址:https://www.cnblogs.com/strinkbug/p/1342699.html