深度探索c++对象模型之template中的名称决议方式

来源:互联网 发布:oracle查看数据库 编辑:程序博客网 时间:2024/04/27 14:14
      我们应该能够区分以下两种意义:一个是c++ standard标准中的“scope of the template definition”【模板定义域】,另一个是c++ standard标准中的“scope of the template instantiation”【模板具现域】。第一种情况举例说明:
// scope of the template definition【模板定义域】extern double foo(double);template<class type>class ScopeRules{public:  void invariant() {  _member = foo( _val ); }type type_dependent() { return foo( _member ); }private:  int _val;  type _member;}

      然后第二种情况也举例说明:

// scope of the template instantiation【模板具现域】extern int foo(int);ScopeRules<int> sr;


      在ScopeRules template中有两个foo版本:在“scope of the template definition”中,只有一个foo函数声明位于scope之内。然而在“scope of the instantiation”中,两个foo函数版本都位于scope之内。这时如果我们有一个这样的调用操作:

// scope of the template instantiationsr.invariant();

那么在invariant中的【_member = foo( _val );】,究竟会调用哪一个函数实体呢?是scope of the template declaration【模板声明域】中的“extern double foo( double )”,还是scope of the template instantiation【模板具现域】中的“extern int foo( int )”?如果您因为在我们例子中用int具现的ScopeRules而选择了后者,那么很可惜您选错了,因为正确答案是意料之外的double foo。。。

      至于原因,让我们来看一下书中的解释:在template之中,对于一个非成员名字【如本例中invariant里面foo】的决议结果,是根据这个名字的使用是否与“用来具现该模板的实际参数类型”有关与否来决定的,如果非成员名字的使用和具现模板用的实际参数没有关联,那么就以“scope of the template declaration【模板声明域】”来决定名字归属;然而如果它们有关联,那么就以“scope of the template instantiation【模板具现域】”来决定名字归属;回头看我们上面的例子可以发现,invariant中的foo与我们用来具现模板的参数int没有关联,所以使用“scope of the template declaration”中的double版本foo函数,下面是更详细的解释:

// the  resolution fo foo() is not dependent on the template argument【foo函数的决议结果并不依赖于模板参数】_member = foo( _val );
_val在我们的模板声明中,已经被定义成一个int类型,也就是说,_val是一个类型不会变的模板类成员,无论具现这个ScopeRules的实际参数是什么类型,都不会影响到_val本身。还有,函数的决议结果只和函数的signature【原型】有关,和函数的返回值类型什么的无关,所以,模板具现后的_member类型并不会影响到哪一个foo函数体被选中,总之就是foo的调用与具现ScopeRules的参数毫无关联!所以调用操作必须根据“scope of the template declaration”来决议,而在“scope of the template declaration”域中,只有一个double版本foo函数,所以自然只有一个候选者。【此外要注意的是,这种行为不能以一个简单的宏扩展——比如使用一个#define宏——重现之】。

      下面让我们来看看“与具现模板类型”【type-dependent】有关的用法:

sr.type_dependent();
这个函数的内容如下:

return foo(_member);
这个例子与上一个例子不同,因为_member肯定与具现ScopeRules的参数有关:该参数将决定_member的实际类型。所以这一次foo必须在“scope of the template instantiation”域中被决议,到了这个域中就有了两个foo版本函数,但由于_member的被具现后的类型是int,因此这次就是int版本的foo函数出线。但是,如果ScopeRules是被unsigned int或long具现出来,那么这里的foo选择就会模糊不清。最后,如果ScopeRules是被某一个用户自己的自定义类类型具现出来,而该类没有针对int和double实现conversion运算符【转换运算符】,那么foo的调用操作会被标识错误!但不管情况如何,都是以“scope of the template instantiation”来决定,而不是“scope of the template declaration”来决定。

      这意味着编译器必须保持两个scope contexts【上下文范围】:

1):“scope of the template declaration”,用来专注于一般的template class;

2):“scope of the template instantiation”,用来专注于特定的实体;

编译器的resolution【决议】算法必须决定哪一个才是适当的scope,然后在其中搜索适当的name。





1 0
原创粉丝点击