您的位置:首页 > 编程语言 > C语言/C++

《c++ templates》学习笔记(8)——第十一章 模板实参演绎

2008-11-27 23:06 288 查看

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

}

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

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

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

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

1.2 节接受的实参转型

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

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

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

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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: